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

移动开发
通过阅读本文你能学习到: 1、ViewDragHelper的使用(如果你想学习自定义View,那么ViewDragHelper你绝对不能错过) 2、好像也没有什么了.... 这个效果,难度不大,会ViewDragHelper的同学应该10分钟就能写出来了吧~如果不会也没关系~

今天带大家实现简书的滑动返回效果.

先看看效果图:

最终效果图.gif

因为没有具体内容,也没有简书的图片资源,所以稍微简陋了点.
但是依然不妨碍我们的效果展示~

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

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

这个效果,难度不大,会ViewDragHelper的同学应该10分钟就能写出来了吧~
如果不会也没关系~

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

1.1 因为看到左边黄色的View是被遮住的,而另外一个View的宽度是MatchParent的,所以FrameLayout是不错的选择.
顺便增加一个回调,通知activity去finish

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

1.2 Xml布局,非常简单:

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

1.3 实例化一个ViewDragHelper

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

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

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

1.5 让ViewDragHelper处理touch事件

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

1.6重写ViewDragHelper的一些处理方法
已附上详细注释

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

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

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

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

2.定义activity的finish动画

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

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

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

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

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

吐槽一下,简书对代码块的支持太差了,代码复制过来全是乱的!!
同学们还是去看源码吧:

源码在我的Github

责任编辑:倪明 来源: 简书
相关推荐

2009-07-06 19:29:37

云计算私有云服务器虚拟化

2022-08-29 15:19:09

CSS烟花动画

2018-03-07 15:24:41

PythonMySQL

2020-10-28 15:03:25

C+代码开发

2011-06-07 16:03:48

匿名SQL Server

2009-12-17 08:57:28

Windows 7磁盘分区

2024-07-22 11:43:28

LVMPnetLab网络

2024-09-13 15:20:46

2017-11-29 11:14:52

离线缓存URL协议缓存

2018-06-11 15:30:12

2013-03-18 16:09:27

JavaEEOpenfire

2024-11-01 11:40:11

2017-12-25 11:50:57

LinuxArch Linux

2012-03-22 10:33:33

思杰XenDesktop

2009-12-18 16:27:43

Cisco路由器配置

2023-09-05 07:52:43

2017-09-28 09:40:36

图像分类准确率

2022-09-30 15:37:19

Web网站服务器

2010-10-08 14:48:32

TFSVisual Stud

2017-08-24 08:31:41

点赞
收藏

51CTO技术栈公众号