Android NestedScrolling 机制-基础篇

本文字数:4688

预计阅读时间:16分钟

VideoDownload

下载b站、抖音视频仅用于学习。

Android NestedScrolling 机制-基础篇

其实NestedScrolling对于现在的Android开发已经是一个很常见的交互效果,当我们需要实现一些好看却又比较复杂的滑动变换时,基本上就需要借助NestedScrolling机制。

先看下一个比较常见的示例效果


这套效果是利用官方提供的CoordinatorLayout实现的,当然CoordinatorLayout就是NestedScrolling机制典型的官方应用例子。

一 对比

这里我会先介绍下基础的概念和机制实现,后续结合对整个机制的理解实现一个简单模仿NestedScrollView的Demo,以便更好的加深理解。

 效果如图:


传统的View事件分发机制

传统事件分发处理主要涉及到Activity、ViewGroup和View这三个主要的类。

  • 事件分发机制 对应分发方法是dispatchTouchEvent ,只要事件能够传递到当前处理的View,则此方法一定被调用。

  • 事件拦截机制对应的拦截方法是onInterceptTouchEvent,拦截之后则不往下传递。(此方法只有ViewGroup拥有,此方法会在dispatchTouchEvent 中被调用。

  • 事件的响应机制对应的是onTouchEvent方法。

对于传统的事件从分发,拦截到处理的一般流程:

  1. 由当前的Activity接收系统的Touch事件回调,调用dispatchTouchEvent开始分发Touch事件

  2. 上层ViewGroup根据onInterceptTouchEvent判断是否要中断Touch事件

  • 中断,则拦截Touch事件,并会回调onTouchEvent,进行处理

  • 不中断,则继续调用其子View的dispatchTouchEvent继续分发Touch事件

  1. 直到有子View消费掉了Touch事件,则整个过程就结束了

传统的Touch事件分发是由上向下的整个过程类似于一个单向的水流事件,中间有一环将水流拦截,则下游便不会再有水流经过。

这样导致的问题,就是在一个Touch事件流中,只能有一个View或ViewGroup对当前Touch事件做出反应。

原则上当Touch事件被拦截后,是无法再次交还给下层子View去处理的(除非手动干预事件的分发)。

因此我们示例中的滑动效果,我们滑动的是下面的内容区域View,但是滚动的却是外部的ViewGroup,那么就必须由上面的ViewGroup拦截Touch事件并进行处理。

而示例效果确实上层的ViewGroup滑动一定程度后,又交换给了下面的子View进行滑动处理,显然这种无间断顺滑交互,按照传统的Touch事件的分发机制,是很难实现的。

由此就引出了我们今天的主角NestedScrolling机制。

NestedScrolling机制

基础流程大致是这样的:

  1. 首先需要原有的Touch事件处理先交给子View,当然父View可以拦截,拦截后本次处理便无法交给子View去处理了

  2. 当子View接收到Touch事件时,会转换为NestedScrolling事件,也就是dx,dy (后续统称为NestedScrolling事件),并开始发起NestedScrolling事件分发。

  3. 子View首先将对应的NestedScrolling事件发送给父View处理,待父View处理完成后则返回对应的处理和未处理的偏移量

  4. 子View根据剩余偏移量继续处理NestedScrolling事件,并再次通知父View处理剩余的偏移量

  5. 父View处理完成,子view则最后发起NestedScrolling事件终结,父view进行收尾工作

从上述的流程中可以轻易的得出NestedScrolling事件,是一种由下向上发起,但是在处理过程中,会不断询问上层View的处理,整个过程是给予了上层和下层多个参与处理的机会。

不难得出NestedScroll的机制本质上是给View与View之间提供了一种关联的机制,以实现View之间协同处理原来的Touch事件,来解决传统Touch事件机制无法回溯到父View的一锤子买卖的问题。当然其中的前提条件是子View需要作为Touch事件的处理者。

二 实现

1 主要接口
- NestedScrollingParent
- NestedScrollingChild
最新的支持库中,还有
- NestedScrollingParent2
- NestedScrollingChild2
由于新增的两个类原理上不影响对NestedScrolling机制的分析,在此就不对这两个类多做描述。

首先了解一下NestedScrollingParent的接口方法

 boolean onStartNestedScroll(@NonNull View child, @NonNull View target, @ScrollAxis int axes);
 void onNestedScrollAccepted(@NonNull View child, @NonNull View target, @ScrollAxis int axes);
 void onStopNestedScroll(@NonNull View target);
 void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
            int dxUnconsumed, int dyUnconsumed);
 void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed);
 boolean onNestedFling(@NonNull View target, float velocityX, float velocityY, boolean consumed);
 boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY);
 int getNestedScrollAxes();

首先Parent中的方法基本都是on开头的响应式的方法,我们这里需要着重关注这几个方法

  • onStartNestedScroll 对发起嵌套滑动的子view做出回应,这个子View不一定是直接子View,例如viewPager嵌套的RecycleView。如果此父View接受嵌套滚动操作,则需要返回true。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值