一步一步教你150行代码实现简书滑动返回效果

先看看效果图:java

 

由于没有具体内容,也没有简书的图片资源,因此稍微简陋了点.
可是依然不妨碍咱们的效果展现~android

OK,接下来惯例,经过阅读本文你能学习到:git

  1. ViewDragHelper的使用(若是你想学习自定义View,那么ViewDragHelper你绝对不能错过)
  2. 好像也没有什么了….

这个效果,难度不大,会ViewDragHelper的同窗应该10分钟就能写出来了吧~
若是不会也不要紧~github

1. 咱们自定义一个SwipeBackFrameLayout继承自FrameLayout

1.1 由于看到左边黄色的View是被遮住的,而另一个View的宽度是MatchParent的,因此FrameLayout是不错的选择.
顺便增长一个回调,通知activity去finishide

1
2
3
4
5
6
7
public void setCallback(Callback mCallback){
      this .mCallback = mCallback;
}
private Callback mCallback;
public interface Callback{
      void onShouldFinish();
}
 

1.2 Xml布局,很是简单:布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
< yifeiyuan.practice.practicedemos.drager.SwipeBackFrameLayout
      xmlns:android = "http://schemas.android.com/apk/res/android"
      xmlns:tools = "http://schemas.android.com/tools"
      android:id = "@+id/swipe_back"
      android:layout_width = "match_parent"
      android:layout_height = "match_parent"
      tools:context = "yifeiyuan.practice.practicedemos.drager.SwipeBackActivity" >
      < TextView
            android:layout_width = "40dp"
            android:layout_height = "match_parent"
            android:text = "@string/hello_world"
            android:gravity = "center"
            android:background = "#ffff00" />
      < View
            android:layout_width = "match_parent"
            android:layout_height = "match_parent"
            android:background = "#ff00ff" />
</ yifeiyuan.practice.practicedemos.drager.SwipeBackFrameLayout >
 

1.3 实例化一个ViewDragHelper学习

1
2
3
4
5
6
7
8
9
//1f表明灵敏度
mDragHelper = ViewDragHelper.create( this , 1f, new ViewDragHelper.Callback() {
      @Override
      public boolean tryCaptureView(View child,  int pointerId) {
           return false ;
      }
}
//由于咱们是从左向右滑动 因此设置EDGE_LEFT
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
 

1.4 在SwipeBackFrameLayout里实例化xml里的子View动画

1
2
3
4
5
6
7
8
9
private View mDividerView;
private View mContentView;
@Override
protected void onFinishInflate() {
      super .onFinishInflate();
      mDividerView = getChildAt( 0 );
      mDividerView.setAlpha(0f);
      mContentView = getChildAt( 1 );
}
 

1.5 让ViewDragHelper处理touch事件this

1
2
3
4
5
6
7
8
9
10
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
      return mDragHelper.shouldInterceptTouchEvent(ev);
}
 
@Override
public boolean onTouchEvent(MotionEvent event) {
      mDragHelper.processTouchEvent(event);
      return true ;
}
 

1.6重写ViewDragHelper的一些处理方法spa

已附上详细注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
@Override
public void onEdgeTouched( int edgeFlags,  int pointerId) {
      super .onEdgeTouched(edgeFlags, pointerId);
      //触摸到左边界的时候 咱们capture住mContentView
      mDragHelper.captureChildView(mContentView, pointerId);
}
@Override
public int getViewHorizontalDragRange(View child) {
      return 1 ;
}
 
@Override
public void onViewPositionChanged(View changedView,  int left,  int top,  int dx,  int dy) {
      super .onViewPositionChanged(changedView, left, top, dx, dy);
      Log.d(TAG,  "onViewPositionChanged() called with left = [" + left +  "], top = [" + top +  "], dx = [" + dx +  "], dy = [" + dy +  "]" );
      //0.0 - 1.0
      //Notice 这边能够给个接口回调出去,就能够作各类炫酷的效果了
      float alpha = ( float ) (left* 1.0 /mDividerWidth);
      mDividerView.setAlpha(alpha);
}
 
@Override
public int clampViewPositionHorizontal(View child,  int left,  int dx) {
      // Log.d(TAG, "clampViewPositionHorizontal() called with dx = [" + dx + "]");
      // 计算left 咱们的目标范围是0-dividerwidth的宽度
      mLastdx = dx;
      int newLeft = Math.min(mDividerWidth, Math.max(left, 0 ));
      return newLeft;
}
@Override
public void onViewReleased(View releasedChild,  float xvel,  float yvel) {
      //>0表明用户想关闭
      if (mLastdx> 0 ){
          // 还不到关闭条件,咱们让view滑动过去,再关闭
          if (mDividerWidth != releasedChild.getLeft()) {
               mDragHelper.settleCapturedViewAt(mDividerWidth,releasedChild.getTop();
               invalidate();
          else {
               if (mCallback !=  null ) {
                     mCallback.onShouldFinish();
               }
          }
      } else {
          //用户不想关闭 ,则滑动到最左边
          if (mDividerWidth !=  0 ) {
              mDragHelper.settleCapturedViewAt( 0 , releasedChild.getTop());
              invalidate();
          }
      }
}
 
@Override
public void onViewDragStateChanged( int state) {
      super .onViewDragStateChanged(state);
      //滑动中止,而且到达了滑动的判断条件 则回调关闭
      if (mDragHelper.getViewDragState()==ViewDragHelper.STATE_IDLE&&mCallback !=  null &&mDividerWidth==mContentView.getLeft()&&mLastdx> 0 ) {
           mCallback.onShouldFinish();
      }
}
});
 

1.7 增长对view滑动事件处理,对于以上mDividerWidth咱们在onLayout里获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private int mDividerWidth;
 
@Override
protected void onLayout( boolean changed,  int left,  int top,  int right,  int bottom) {
       super .onLayout(changed, left, top, right, bottom);
       mDividerWidth = mDividerView.getWidth();
}
//Notice view 刚初始化的时候就会被调用一次
@Override
public void computeScroll() {
      super .computeScroll();
      // Log.d(TAG, "computeScroll() called with " + "");
      if (mDragHelper.continueSettling( true )) {
           invalidate();
      }
}
 

咱们写完自定义view后还须要自定义一下activity的退出动画~

2.定义activity的finish动画

2.1 在anim目录下,建立两个动画xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//no_anim
< alpha
      android:duration = "300"
      xmlns:android = "http://schemas.android.com/apk/res/android"
      android:fromAlpha = "1.0"
      android:toAlpha = "1.0" >
</ alpha >
 
//out_to_right
< translate
      xmlns:android = "http://schemas.android.com/apk/res/android"
      android:duration = "300"
      android:fromXDelta = "0%"
      android:toXDelta = "100%" >
</ translate >
 

2.2 在activity里设置callback监听,并运用动画

1
2
3
4
5
6
7
mSwipeBack.setCallback( new SwipeBackFrameLayout.Callback() {
       @Override
       public void onShouldFinish() {
             finish();
             overridePendingTransition(R.anim.no_anim, R.anim.out_to_right);
       }
});
 

好了!!~代码量很是少!~就是这么简单~

吐槽一下,简书对代码块的支持太差了,代码复制过来全是乱的!!

同窗们仍是去看源码吧:

源码在个人Github

原文:http://www.jianshu.com/p/59be4551c418

相关文章
相关标签/搜索