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
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值