zoukankan      html  css  js  c++  java
  • 一步一步教你150行代码实现简书滑动返回效果

    先看看效果图:

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

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

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

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

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

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

    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: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事件

    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的一些处理方法

    已附上详细注释

    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"
         android:fromAlpha="1.0"
         android:toAlpha="1.0" >
    </alpha>
     
    //out_to_right
    <translate
         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

  • 相关阅读:
    D. Constructing the Array
    B. Navigation System
    B. Dreamoon Likes Sequences
    A. Linova and Kingdom
    G. Special Permutation
    B. Xenia and Colorful Gems
    Firetrucks Are Red
    java getInstance()的使用
    java 静态代理和动态代理
    java 类加载机制和反射机制
  • 原文地址:https://www.cnblogs.com/shanzei/p/4777712.html
Copyright © 2011-2022 走看看