美文网首页Android开发Android技术知识Android开发
Android 事件分发实例之右滑结束Activity(二)

Android 事件分发实例之右滑结束Activity(二)

作者: Gxinyu | 来源:发表于2019-06-02 12:50 被阅读54次

    前言

    本篇同上一篇实现同样的功能,此篇采用之前音乐锁屏壁纸的功能里面使用的ViewDragHelper来实现,最终的效果与上篇效果相同,因此本篇只挑新内容讲解。

    具体步骤

    事件分发与冲突解决

    @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            boolean canScrollHorizontally = canScrollHorizontally(-1, this);
            if (!canScrollHorizontally) {
                return mViewDragHelper.shouldInterceptTouchEvent(ev);
            }
            return super.onInterceptTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            mViewDragHelper.processTouchEvent(event);
            return true;
        }
    

    说明:上一篇已经说清一个事件里面包含三个小事件,因为此篇主要是把事件交由ViewDragHelper处理,因此处理canScrollHorizontally()方法时,判断条件不能只放在Move事件中处理,否则Down、Up的事件ViewDragHelper接收不到,查看源码知道mViewDragHelper.shouldInterceptTouchEvent(ev)和mViewDragHelper.processTouchEvent(event)方法必须要三个事件同时存在。

    滑动处理

    通过ViewDragHelper实现滑动效果,主要是通过实现ViewDragHelper的回调ViewDragHelper.Callback实现滑动效果。

            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return false;
            }
    
            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                //当前回调,松开手时触发,比较触发条件和当前的滑动距离
                int left = releasedChild.getLeft();
                if (left <= mMaxSlideWidth) {
                    //缓慢滑动的方法,小于触发条件,滚回去
                    mViewDragHelper.settleCapturedViewAt(0, 0);
                } else {
                    //大于触发条件,滚出去...
                    mViewDragHelper.settleCapturedViewAt(mScreenWidth, 0);
                }
    
                //需要手动调用更新界面的方法
                invalidate();
            }
    
            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                mScrollPercent = Math.abs((float) left
                        / (mScreenWidth + mEdgeShadow.getIntrinsicWidth()));
                //重绘
                invalidate();
    
                //当滚动位置到达屏幕最右边,则关掉Activity
                if (changedView == mRootView && left >= mScreenWidth) {
                    mActivity.finish();
                }
            }
    
            @Override
            public int getViewHorizontalDragRange(View child) {
                return ViewDragHelper.EDGE_LEFT;
            }
    
            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                //限制左右拖拽的位移
                left = left >= 0 ? left : 0;
                return left;
            }
    
            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                //上下不能移动,返回0
                return 0;
            }
    
            @Override
            public void onEdgeDragStarted(int edgeFlags, int pointerId) {
                //触发边缘时,主动捕捉mRootView
                mViewDragHelper.captureChildView(mRootView, pointerId);
            }
    

    说明:1、tryCaptureView():由用户决定捕获哪个子View的行为,由于我们是移动整个ViewGroup,直接返回false。
    2、onViewReleased():当视图拖拽完成时回调,主要处理松手之后视图最终位置,mViewDragHelper.settleCapturedViewAt(0, 0)方法内部也是通过调用Scroller来实现移动
    3、onViewPositionChanged():看方法名称就知道View位置改变的时候回调,因此可以通过判断最后的位置是否超过右边缘来结束activity
    4、getViewHorizontalDragRange():获取当前水平方向的范围,右滑,设置左边缘即可
    5、clampViewPositionHorizontal():限制水平方向的位置,默认不限制,因此需要重写限制大于0,这样就可以实现右滑
    6、clampViewPositionVertical():限制垂直方向上的位置,右滑可以不重写
    7、onEdgeDragStarted():无子类捕获,父类从之前设置的边缘拖拽的时候回调,此时去捕获activity的视图

    @Override
        public void computeScroll() {
            //使用settleCapturedViewAt方法是,必须重写computeScroll方法,传入true
            //持续滚动期间,不断刷新ViewGroup
            if (mViewDragHelper.continueSettling(true))
                ViewCompat.postInvalidateOnAnimation(this);
        }
    

    说明:mViewDragHelper.continueSettling(true)方法在拖拽过程中通过返回值不断的回调,使拖拽过程更加平滑,与mViewDragHelper.settleCapturedViewAt(0, 0)呼应,主要还是利用Scroller的滑动机制。

    触摸范围

    完成上述步骤已经可以实现右滑,只是ViewDragHelper内部检测是否是边缘,然后才能去拖拽。ViewDragHelper源码默认的边缘是20dp,如果想实现全屏拖拽的效果必须修改此值,查看ViewDragHelper源码并没有可以修改边缘宽度的方法,因此采用反射来实现。

    /**
         * 设置可以拖拽的触点范围
         *
         * @param touchRange
         */
        private void setTouchRange(int touchRange) {
            Class<?> aClass = mViewDragHelper.getClass();
            Field mDividerHeight = null;
            try {
                mDividerHeight = aClass.getDeclaredField("mEdgeSize");
                mDividerHeight.setAccessible(true);
                mDividerHeight.setInt(mViewDragHelper, touchRange);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    总结

    本篇采用与上篇不同的方式,主要不同点是事件处理的时机问题和触摸范围的修改,还有ViewDragHelper的各个回调方法处理,其他方面没区别,现已完成测试,效果与上篇完全一致。现在还在做进一步的封装,后续会持续更新最新代码。
    右滑结束Activity

    相关文章

      网友评论

        本文标题:Android 事件分发实例之右滑结束Activity(二)

        本文链接:https://www.haomeiwen.com/subject/lvbstctx.html