资讯专栏INFORMATION COLUMN

嵌套滚动机制

Riddler / 2509人阅读

摘要:在这之前,我们知道对事件的分发是有自己一套机制的。该方法的第三第四个参数返回父消费掉的长度和子的窗体偏移量。三向父汇报滚动情况,包括子消费的部分和子没有消费的部分。

谷歌在发布安卓 Lollipop版本之后,为了更好的用户体验,Google为Android的滑动机制提供了NestedScrolling特性

NestedScrolling的特性

比如你使用了Toolbar,下面一个ScrollView,向上滚动隐藏Toolbar,向下滚动显示Toolbar,这里在逻辑上就是一个NestedScrolling —— 因为你在滚动整个Toolbar在内的View的过程中,又嵌套滚动了里面的ScrollView。

在这之前,我们知道Android对Touch事件的分发是有自己一套机制的。主要是有是三个函数:

dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。

这种分发机制让移动应用安全检测平台-爱内测(ineice.com)发现有一个漏洞,据爱内测的CTO介绍:

如果子view获得处理touch事件机会的时候,父view就再也没有机会去处理这个touch事件了,直到下一次手指再按下。

也就是说,我们在滑动子View的时候,如果子View对这个滑动事件不想要处理的时候,只能抛弃这个touch事件,而不会把这些传给父view去处理。

但是Google新的NestedScrolling机制就很好的解决了这个问题。

我们看看如何实现这个NestedScrolling,首先有几个类(接口)我们需要关注一下

NestedScrollingChild

NestedScrollingParent

NestedScrollingChildHelper

NestedScrollingParentHelper

以上四个类都在support-v4包中提供,Lollipop的View默认实现了几种方法。

实现

实现接口很简单,这边我暂时用到了NestedScrollingChild系列的方法(因为Parent是support-design提供的CoordinatorLayout)

    @Override

    public void setNestedScrollingEnabled(boolean enabled) {

        super.setNestedScrollingEnabled(enabled);

        mChildHelper.setNestedScrollingEnabled(enabled);

    }

 

    @Override

    public boolean isNestedScrollingEnabled() {

        return mChildHelper.isNestedScrollingEnabled();

    }

    @Override

    public boolean startNestedScroll(int axes) {

        return mChildHelper.startNestedScroll(axes);

    }

    @Override

    public void stopNestedScroll() {

        mChildHelper.stopNestedScroll();

    }

    @Override

    public boolean hasNestedScrollingParent() {

        return mChildHelper.hasNestedScrollingParent();

    }

    @Override

    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {

        return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);

    }

    @Override

    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {

        return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);

    }

    @Override

    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {

        return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);

    }

    @Override

    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {

        return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);

    }

对,简单的话你就这么实现就好了。

这些接口都是我们在需要的时候自己调用的。childHelper干了些什么事呢?,看一下startNestedScroll方法

    /**

     * Start a new nested scroll for this view.

     *

     * 

This is a delegate method. Call it from your {@link android.view.View View} subclass * method/{@link NestedScrollingChild} interface method with the same signature to implement * the standard policy.

* * @param axes Supported nested scroll axes. * See {@link NestedScrollingChild#startNestedScroll(int)}. * @return true if a cooperating parent view was found and nested scrolling started successfully */ public boolean startNestedScroll(int axes) { if (hasNestedScrollingParent()) { // Already in progress return true; } if (isNestedScrollingEnabled()) { ViewParent p = mView.getParent(); View child = mView; while (p != null) { if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes)) { mNestedScrollingParent = p; ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes); return true; } if (p instanceof View) { child = (View) p; } p = p.getParent(); } } return false; }

可以看到这里是帮你实现一些跟NestedScrollingParent交互的一些方法。

ViewParentCompat是一个和父view交互的兼容类,它会判断api version,如果在Lollipop以上,就是用view自带的方法,否则判断是否实现了NestedScrollingParent接口,去调用接口的方法。

那么具体我们怎么使用这一套机制呢?比如子View这时候我需要通知父view告诉它我有一个嵌套的touch事件需要我们共同处理。那么针对一个只包含scroll交互,它整个工作流是这样的:

一、startNestedScroll

首先子view需要开启整个流程(内部主要是找到合适的能接受nestedScroll的parent),通知父View,我要和你配合处理TouchEvent

二、dispatchNestedPreScroll

在子View的onInterceptTouchEvent或者onTouch中(一般在MontionEvent.ACTION_MOVE事件里),调用该方法通知父View滑动的距离。该方法的第三第四个参数返回父view消费掉的scroll长度和子View的窗体偏移量。如果这个scroll没有被消费完,则子view进行处理剩下的一些距离,由于窗体进行了移动,如果你记录了手指最后的位置,需要根据第四个参数offsetInWindow计算偏移量,才能保证下一次的touch事件的计算是正确的。

如果父view接受了它的滚动参数,进行了部分消费,则这个函数返回true,否则为false。

这个函数一般在子view处理scroll前调用。

三、dispatchNestedScroll

向父view汇报滚动情况,包括子view消费的部分和子view没有消费的部分。

如果父view接受了它的滚动参数,进行了部分消费,则这个函数返回true,否则为false。

这个函数一般在子view处理scroll后调用。

四、stopNestedScroll

结束整个流程。

整个对应流程是这样

子view 父view

startNestedScroll onStartNestedScroll、onNestedScrollAccepted

dispatchNestedPreScroll onNestedPreScroll

dispatchNestedScroll onNestedScroll

stopNestedScroll onStopNestedScroll

一般是子view发起调用,父view接受回调。

我们最需要关注的是dispatchNestedPreScroll中的consumed参数。

public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) ;

它是一个int型的数组,长度为2,第一个元素是父view消费的x方向的滚动距离;第二个元素是父view消费的y方向的滚动距离,如果这两个值不为0,则子view需要对滚动的量进行一些修正。正因为有了这个参数,使得我们处理滚动事件的时候,思路更加清晰,不会像以前一样被一堆的滚动参数搞混。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/13762.html

相关文章

  • NestedScrolling(Android嵌套滑动机制

    摘要:再次感谢在发布版本后,为了更好的用户体验,为的滑动机制提供了机制。如图在这之前,我们知道对事件分发是有自己的一套机制。主要是有三个函数。简单逻辑这样就可以实现嵌套滑动。三向父汇报滚动情况,包括子已消费和未消费的值。四结束整个嵌套滑动流程。 终于要在segmentfault写第一篇文章了,好鸡冻,这篇文章本来打算写在简书上的,但是由于页面不能富文本和markdown同时支持,看到Gemi...

    mengbo 评论0 收藏0
  • Android 嵌套滑动机制(NestedScrolling)

    摘要:效果如上图别嫌弃我在这之前,我们知道对事件的分发是有自己一套机制的。主要是有是三个函数和。该方法的第三第四个参数返回父消费掉的长度和子的窗体偏移量。三向父汇报滚动情况,包括子消费的部分和子没有消费的部分。 Android 在发布 Lollipop版本之后,为了更好的用户体验,Google为Android的滑动机制提供了NestedScrolling特性 NestedScrol...

    CoffeX 评论0 收藏0
  • 滑动 - 收藏集 - 掘金

    摘要:分析提到侧滑删除,一个经典的例子就是玩转仿探探卡片式滑动效果掘金讲起本篇博客的历史起源,估计有一段历史了。列表左右滑动开源组件掘金是一款用于为上的排布提供左滑右滑操作的库。 Android 仿 YouTube 拖拽视频效果的实现 - Android - 掘金Android仿YouTube拖拽视频效果的实现 youtube-like-drag-video-view 代码已经开源到GitH...

    ShevaKuilin 评论0 收藏0
  • 10分钟带你入门NestedScrolling机制

    摘要:在收到事件时,找到离自己最近的,与它进行绑定并关闭它的事件拦截机制。所以需要主动拦截这种事件,拦截标准超过的距离。当前触摸的不是支持机制的。这种机制将滑动事件的传递封装起来,通过辅助类实现和之间的连接和交互。 一、从一个简单的DEMO看什么是嵌套滚动 我们先来看一下DEMO的效果,直观的感受一下什么是嵌套滚动: showImg(https://segmentfault.com/img/...

    betacat 评论0 收藏0
  • Android列表,嵌套滑动

    摘要:那些酷炫的开源库整理整理开源库,文章提交,欢迎提交更新二维可拖动面板控件控件可用于房态盘计划表待办事项课程表等相关需要二维视图的场合,需要的可以收藏下五分钟带你看懂嵌套滑动机制在发布之后加入了嵌套滑动机制为嵌套滑动提供了更方便的处理方案。 仿淘宝、京东拖拽商品详情(可嵌套ViewPager、ListView、WebView、FragmentTabhost) 对于电商App,商品详情无疑...

    aboutU 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<