Android 5.0 嵌套滑动NestedScrolling 源码解析

转载请注明出处 http://blog.csdn.net/u011453163/article/details/52751110

国庆假期终于要结束了,懒散了几天 。加上之前的微信小程序事件,赶紧写篇博客压压惊。

android 传统的事件派发 从外到内层层派发,当其中某一组件消化了事件之后即事件派发结束,无法回馈到外部组件。

Android5.0以后 官方提供了一套嵌套滑动的事件派发机制。当然也兼容5.0一下版本

support-v4 版本应该在22以上

提供了几个类
public interface NestedScrollingChild
public class NestedScrollingChildHelper (至关重要)
public interface NestedScrollingParent
public class NestedScrollingParentHelper

总共是两个接口和两个辅助类

用一个简单的图表示一下我的理解
这里写图片描述

NestedScrollingChild中的方法
这里写图片描述
这个接口的方法在5.0以上的View已经包含了 在5.0以下版本是没用这些方法的,所以NestedScrollingChild基本上就为了兼容低版本所提供的接口类。同理
NestedScrollingParent也是为低版本提供一些回调方法,但是它还是一个非常重要的角色
这里写图片描述

接下来是两个辅助类
NestedScrollingParentHelper基本没做什么事
这里写图片描述

NestedScrollingChildHelper则是一个非常重要的存在,基本是嵌套滑动的所有逻辑都在从这个类里面实现的。也是今天的关键。
这里写图片描述
这是四个类的方法。

根据上面简单的图解 嵌套滑动的关键是事件从内往外传递。这也是源码的思想。
嵌套滑动最开始是从

NestedScrollingChildHelper 的 startNestedScroll开始的,我也从这里开始分析源码的走向

 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;
    }

这段代码的大致意思是要告诉外层组件 要开始滑动啦。外层组件??谁是外层的组件,外层组件那么怎么知道具体要通知谁呢??
可以看到这段代码有一个遍历外部组件的过程

 if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes)) {
                    mNestedScrollingParent = p;
                    ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes);
                    return true;
                }

谁是满足条件的呢???
跟进源码

public static boolean onStartNestedScroll(ViewParent parent, View child, View target,
            int nestedScrollAxes) {
        return IMPL.onStartNestedScroll(parent, child, target, nestedScrollAxes);
    }

源码真心不错。

@Override
        public void onNestedScrollAccepted(ViewParent parent, View child, View target,
                int nestedScrollAxes) {
            if (parent instanceof NestedScrollingParent) {
                ((NestedScrollingParent) parent).onNestedScrollAccepted(child, target,
                        nestedScrollAxes);
            }
        }

看到里面的实现 可以看出这外层的组件必须是实现了NestedScrollingParent接口的 这也是刚刚为什么说是一个重要的角色的原因。

外层的组件找到了 那剩下的就是的就是通知啦
其实从startNestedScroll这个方法的思想 其他的滑动事件的回馈基本都是一样的了

public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
        if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
            if (dx != 0 || dy != 0) {
                int startX = 0;
                int startY = 0;
                if (offsetInWindow != null) {
                    mView.getLocationInWindow(offsetInWindow);
                    startX = offsetInWindow[0];
                    startY = offsetInWindow[1];
                }

                if (consumed == null) {
                    if (mTempNestedScrollConsumed == null) {
                        mTempNestedScrollConsumed = new int[2];
                    }
                    consumed = mTempNestedScrollConsumed;
                }
                consumed[0] = 0;
                consumed[1] = 0;
                ViewParentCompat.onNestedPreScroll(mNestedScrollingParent, mView, dx, dy, consumed);

                if (offsetInWindow != null) {
                    mView.getLocationInWindow(offsetInWindow);
                    offsetInWindow[0] -= startX;
                    offsetInWindow[1] -= startY;
                }
                return consumed[0] != 0 || consumed[1] != 0;
            } else if (offsetInWindow != null) {
                offsetInWindow[0] = 0;
                offsetInWindow[1] = 0;
            }
        }
        return false;
    }

这里一大堆关于坐标 位置的计算 都没啥用 关键还得传递出去

ViewParentCompat.onNestedPreScroll(mNestedScrollingParent, mView, dx, dy, consumed);

这才是关键
跟进源码 看到的原理还是一样的

 @Override
        public void onNestedPreScroll(ViewParent parent, View target, int dx, int dy,
                int[] consumed) {
            if (parent instanceof NestedScrollingParent) {
                ((NestedScrollingParent) parent).onNestedPreScroll(target, dx, dy, consumed);
            }
        }

一个简单的接口回调。。。 基本上的源码流程就是这样啦

用法是
1 外层组件 实现NestedScrollingParent
内层组件 实现NestedScrollingChild

2 内层组件在时间监听的时候 使用NestedScrollingChildHelper做一些事件的向外通知

3 外层组件通过回调的方法处理实际业务

关于嵌套滑动的源码解析到此为止 有什么不对欢迎指出。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值