150行代码实现滑动退出

2015-09-09 ZhangTitanjum 更多博文 » 博客 » GitHub »

android 滑动退出

原文链接 https://jungletian.github.io/2015/09/09/150%E8%A1%8C%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%E6%BB%91%E5%8A%A8%E9%80%80%E5%87%BA/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


超级简单代码实现滑动退出

本文参考自 http://www.jianshu.com/p/59be4551c418

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

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

这个效果,难度不大,会ViewDragHelper的同学应该10分钟就能写出来了吧~ 如果不会也没关系~以下是代码,请查看。

<!--more-->

  • 自定义Layout : SwipeBackFrameLayout

    public class SwipeBackFrameLayout extends FrameLayout {
        private ViewDragHelper mDragHelper;
        private int mDividerWidth = 100;
        private int mLastdx;
        public SwipeBackFrameLayout(Context context) {
            super(context);
            initView();
        }
        public SwipeBackFrameLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView();
        }
        public SwipeBackFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initView();
        }
        @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();
            if (mDragHelper.continueSettling(true)) {
                invalidate();
            }
        }
        private void initView() {
            // 1f代表灵敏度
            mDragHelper = ViewDragHelper.create(this, 1f, new ViewDragHelper.Callback() {
                @Override
                public void onViewDragStateChanged(int state) {
                    super.onViewDragStateChanged(state);
                    //滑动停止,并且到达了滑动的判断条件 则回调关闭
                    if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE && mcCallBack != null && mDividerWidth == mContentView.getLeft() && mLastdx > 0) {
                        mcCallBack.onShouldFinish();
                    }
                }
                @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("ZTJ", "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) {
                    // 计算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 (mcCallBack != null) {
                                mcCallBack.onShouldFinish();
                            }
                        }
                    } else {
                        //用户不想关闭 ,则滑动到最左边
                        if (mDividerWidth != 0) {
                            mDragHelper.settleCapturedViewAt(0, releasedChild.getTop());
                            invalidate();
                        }
                    }
                }
                @Override
                public boolean tryCaptureView(View child, int pointerId) {
                    return false;
                }
            });
            // 滑动范围
            mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
        }
        // 右侧要出现的View
        private View mDividerView;
        // 内容
        private View mContentView;
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            mDividerView = getChildAt(0);
            mDividerView.setAlpha(0f);
            mContentView = getChildAt(1);
        }
        // 设置finish 回调
        public void setCallBack(CallBack mCallBack) {
            this.mcCallBack = mCallBack;
        }
        private CallBack mcCallBack;
        public interface CallBack {
            void onShouldFinish();
        }
        // 让ViewDragHelper来处理Touch事件
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            return mDragHelper.shouldInterceptTouchEvent(ev);
        }
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            mDragHelper.processTouchEvent(event);
            return true;
        }
    }
    
  • layout.xml : activity_main.xml

    <io.github.jungletian.gradle_export_jar.SwipeBackFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/swipe_back"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="40dp"
            android:layout_height="match_parent"
            android:background="#ffff00"
            android:gravity="center"
            android:text="@string/hello_world" />
        <View
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ff00ff" />
    </io.github.jungletian.grad
    le_export_jar.SwipeBackFrameLayout>
    
  • 动画 : no_anim.xml 与 out_to_right.xml

    <alpha
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="300"
        android:fromAlpha="1.0"
        android:toAlpha="1.0"></alpha>
    

    <translate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="300"
        android:fromXDelta="0%"
        android:toXDelta="100%"></translate>
    
  • Activity :

    public class MainActivity extends AppCompatActivity {
        SwipeBackFrameLayout mSwipeBack;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mSwipeBack = (SwipeBackFrameLayout) findViewById(R.id.swipe_back);
            mSwipeBack.setCallBack(new SwipeBackFrameLayout.CallBack() {
                @Override
                public void onShouldFinish() {
                    finish();
                    overridePendingTransition(R.anim.no_anim, R.anim.out_to_right);
                }
            });
        }
    }