首页 存档 技术 查看内容

【新控件】深入了解 Android Nested Scrolling

2018-3-30 13:00 |来自: 互联网 280 0

摘要: Android常规的Touch事件传递机制是自顶向下,由外向内的,一旦确定了事件消费者View,随后的事件都将传递到该View。因为是自顶向下,父控件可以随时拦截事件,下拉刷新、拖拽排序、折叠等交互效果都可以通过这套机制 ...

Android常规的Touch事件传递机制是自顶向下,由外向内的,一旦确定了事件消费者View,随后的事件都将传递到该View。因为是自顶向下,父控件可以随时拦截事件,下拉刷新、拖拽排序、折叠等交互效果都可以通过这套机制完成。Touch事件传递机制是Android开发必须掌握的基本内容。但是这套机制存在一个缺陷:子View无法通知父View处理事件。NestedScrolling就是为这个场景设计的。

NestedScrollingChild和NestedScrollingParent

NestedScrolling是指存在嵌套滚动的场景,常见于下拉刷新、展开/收起标题栏等。Support包中的CoordinatorLayoutScrollRefreshLayout就是基于NestedScrolling机制实现的。

NestedScrollingChildNestedScrollingParent分别定义了嵌套子View和嵌套父View需要实现的接口,方法列表分别如下,可以先略过,后面会把这些方法串起来。另外这些方法基本都是通过NestedScrollingChildHelperNestedScrollingParentHelper来实现,一般并不需要手动编写多少逻辑。


通过方法名可以看出,NestedScrollingChild的方法均为主动方法,而NestedScrollingParent的方法基本都是回调方法。这也是NestedScrolling机制的一个体现,子View作为NestedScrolling事件传递的主动方,父View作为被动方。

NestedScrolling机制生效的前提条件是子View作为Touch事件的消费者,在消费过程中向父View发送NestedScrolling事件(注意这里不是Touch事件,而是NestedScrolling事件)。

NestedScrolling事件传递

NestedScrolling机制中,NestedScrolling事件使用dx, dy表示,分别表示子View Touch事件处理方法中判定的x和y方向上的滚动偏移量。

NestedScrolling事件的传递:

  1. 由子View产生NestedScrolling事件;

  2. 发送给父View进行处理,父View处理之后,返回消费的偏移量;

  3. 子View根据父View消费的偏移量计算NestedScrolling事件剩余偏移量;

  4. 根据剩余偏移量判断是否能处理滚动事件;如果处理滚动事件,同时将自身滚动情况通知父View;

  5. 处理结束,事件传递完成。

  1. 这里只说明了一层嵌套的情况,事实上NestedScrolling很可能出现在多重嵌套的场景。对于多重嵌套,步骤2、3、4将事件自底向上进行传递,步骤2中消费的偏移量将记录所有嵌套父View消费偏移量的总和。这里不再重复。

  2. Fling事件的传递和Scroll类似,也不再赘述。

方法调用流程

我们可以把上面的方法根据NestedScrolling事件传递的不同阶段进行分组(Fling跟随Scrolling发生)。

初始阶段:确认开启NestedScrolling,关联父View和子View。



预滚动阶段:子View将事件分发到父View


滚动阶段:子View处理滚动事件。


结束阶段:结束。


下面是一次嵌套滚动(**嵌套)从开始到结束的方法调用时序图:

金色是NestedScrollingChild的方法,为子View主动调用。

紫色是NestedScrollingParent的回调方法,由子View相关方法调用。

橙色为滚动事件被消费的时机

当子View调用startNestedScroll方法时,开始嵌套滚动流程;之后不断循环pre-scroll和scroll两个过程(一般在子View的onTouchEvent的MOVE分支调用);直到手指抬起,子View调用stopNestedScroll方法结束滚动(在结束之前可能进入Fling状态)。

划重点

最重要的一点:pre-scroll过程是子View向父View传递事件的过程,而scroll过程才是子View消耗滚动事件的过程,也就是说父View拥有优先消费事件的权利。

从事件消耗的优先级来看,可以画出这样一张图。

dispatchNestedPreScroll传给父View的是没有被消费的滚动事件,父View消费完之后通过consumed数组返回,如果还有剩余,子View进行消费,并将消费多少和剩余多少再次发给父View。

如果一个View同时作为NestedScrollingChild和NestedScrollingParent,那么在处理onNestedPreScrolling和onNestedScrolling的时候,也要按照自底向上的规则,先让父View处理事件。

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除


路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部