Android Scroll(四)----ViewDragHelper

1.Google在其support库中为我们提供了DrawerLayout和SlidingPaneLayout两个布局来帮助开发者实现侧边栏滑动的效果。但是在这两个布局的背后,却隐藏着一个功能强大的类–ViewDragHelper。通过ViewDragHelper可以实现各种不同的滑动,拖放。

2.下面我们来创建一个类似于QQ滑动侧边栏的布局,初始时显示内容界面,当用户手指滑动超过一段距离时,内容界面侧滑显示菜单界面。

1.初始化ViewDragHelper

ViewDragHelper通常定义在一个viewGroup的内部,并且通过其静态工厂方法进行初始化。

private void initView() {
        viewDragHelper = ViewDragHelper.create(this, callBack);
    }

public static ViewDragHelper create(ViewGroup forParent, Callback cb) 第一个参数实惠要监听的参数view。通常需要的是一个viewgroup。即parentView,第二个参数是一个callBack回调,这个回调就是整个ViewDragHelper的核心逻辑。

2.拦截事件

接下来就是要重写事件拦截方法,将事件传递给ViewDragHelper进行处理。

 @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // shouldInterceptTouchEvent()表示的的就是希望自身消耗掉该事件
        return viewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 将触摸事件传递给ViewDragHelper
        viewDragHelper.processTouchEvent(event);
        return true;
    }
3.处理computeScroll()

因为ViewDragHelper的内部同样是通过scroller来实现平滑移动的,所以也要实现该方法。

 @Override
    public void computeScroll() {

        if (viewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }
4处理callBack回调

通过如下代码来实现ViewDragHelper.CallBack。

 private ViewDragHelper.Callback callBack = new ViewDragHelper.Callback(){

        //  什么时候开始检测触摸事件
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return false;
        }

我们重写了tryCaptureView()方法,通过这个方法,我们可以指定爱创建ViewDragHelper时,参数parentView中哪一个子view可以被移动。例如在本例子中我们定义了一个viewGroup,里面定义了两个子view—menuView和mainView,当指定如下的代码时,则只有mainView是可以拖动的。

private ViewDragHelper.Callback callBack = new ViewDragHelper.Callback(){

        //  什么时候开始检测触摸事件
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            //return false;
            // 如果当触摸的child是manView时开始检测
            return mainView == child;
        }
5具体的滑动方法

public int clampViewPositionHorizontal(View child, int left, int dx)和public int clampViewPositionVertical(View child, int top, int dy)分别对应的是垂直和水平方向上的滑动。如果要实现效果,这两个方法是必须要重写的。默认的是不滑动的,默认值为0,实现两个方法中的一个即可实现滑动的效果。

// 处理水平滑动的时候调用
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left;
        }

        // 处理垂直滑动的时候调用
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return top;
        }

public int clampViewPositionHorizontal(View child, int left, int dx)中的参数left,表示的是向左滑动的距离,dy表示的是增量。 public int clampViewPositionVertical(View child, int top, int dy)中也是类似的处理。通常情况下,只需要返回top和left即可,当需要更加精细的计算padding等属性的时候,需要对left进行一些处理,并且返回一些合适大小的值。
通过以上的的重写的三个方法就可以实现最基本的滑动效果了,当用手拖动mainView的时候就可以跟随手指的滑动而滑动了。

6.代码的优化

scroller类张总有这样的一个效果,当手指离开屏幕的时候,子View滑动回到初始的位置。当时我们使用的是监听ACTION_UP事件,并且调用Scroller类来实现的。这里我么可以使用callBack中的回调方法—public void onViewReleased(View releasedChild, float xvel, float yvel),可以重写这个方法,非常简单的实现当手指离开屏幕后实现的操作。这个方法的内部也是通过scroller类来实现的,这也是重写computeScroll()方法的原因。

    // 手指离开屏幕的时候调用
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
            // 手指离开屏幕后子View缓慢移动到指定的位置
            if (mainView.getLeft() < 500) {
                // 关闭菜单
                viewDragHelper.smoothSlideViewTo(mainView, 0, 0);
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            } else {
                // 打开菜单
                viewDragHelper.smoothSlideViewTo(mainView, 400, 0);
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);

            }
        }

调用smoothSlideViewTo()方法使得mainview移动后距左边小鱼500像素的时候就范元回原来的状态,即坐标的(0,0)点,当其左边距大于500的时候就显示menuView.
其实这两行代码和

scroller.startScroll(x,y.dx,dy);
invalidate();

一样的效果.

7.细节的完善

在viewgroup中的onFinishInflate()方法中按顺序将子view分别定义成menuView和mainView,并且在onSizeChanged()方法中获取到view的宽度,如果徐亚根据view的宽度来处理滑动后的效果,可以用这个值来判断。

 @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        menuView = getChildAt(0);
        mainView = getChildAt(1);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = menuView.getMeasuredWidth();
    }

最终效果:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值