NestedScrolling(嵌套滑动)机制

传统的事件分发:

由父View发起,一旦父View需要自己做滑动效果就要拦截掉事件并通过自己的onTouch进行消耗,这样子View就再没有机会接手此事件,如果自己不拦截交给子View消耗,那么不使用特殊手段的话父View也没法再处理此事件。

NestedScrolling机制:

NestedScrolling就是父View和子View之间的一套滑动交互机制。简单点来说就是要求子View在准备滑动之前将滑动的细节信息传递给父View,父View可以决定是否部分或者全部消耗掉这次滑动,并使用消耗掉的值在子View滑动之前做自己想做的事情,子View会在父View处理完后收到剩余的没有被父View消耗掉的值,然后再根据这个值进行滑动。滑动完成之后如果子View没有完全消耗掉这个剩余的值就再告知一下父View。

具体的类:

父控件需要实现的接口与使用到的类:

NestedScrollingParent(接口)

NestedScrollingParent2(也是接口并继承NestedScrollingParent)

NestedScrollingParentHelper(类)

子控件需要实现的接口与使用到的类:

NestedScrollingChild(接口)

NestedScrollingChild2(也是接口并继承NestedScrollingChild)

NestedScrollingChildHelper(类)

NestedScrollingParent
/**
     * 有嵌套滑动到来了,判断父控件是否接受嵌套滑动
     *
     * @param child            嵌套滑动对应的父类的子类(因为嵌套滑动对于的父控件不一定是一级就能找到的,可能挑了两级父控件的父控件,child的辈分>=target)
     * @param target           具体嵌套滑动的那个子类
     * @param nestedScrollAxes 支持嵌套滚动轴。水平方向,垂直方向,或者不指定
     * @return 父控件是否接受嵌套滑动, 只有接受了才会执行剩下的嵌套滑动方法
     */
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {}

    /**
     * 当onStartNestedScroll返回为true时,也就是父控件接受嵌套滑动时,该方法才会调用
     */
    public void onNestedScrollAccepted(View child, View target, int axes) {}

    /**
     * 在嵌套滑动的子控件未滑动之前,判断父控件是否优先与子控件处理(也就是父控件可以先消耗,然后给子控件消耗)
     *
     * @param target   具体嵌套滑动的那个子类
     * @param dx       水平方向嵌套滑动的子控件想要变化的距离 dx<0 向右滑动 dx>0 向左滑动
     * @param dy       垂直方向嵌套滑动的子控件想要变化的距离 dy<0 向下滑动 dy>0 向上滑动
     * @param consumed 这个参数要我们在实现这个函数的时候指定,回头告诉子控件当前父控件消耗的距离
     *                 consumed[0] 水平消耗的距离,consumed[1] 垂直消耗的距离 好让子控件做出相应的调整
     */
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {}

    /**
     * 嵌套滑动的子控件在滑动之后,判断父控件是否继续处理(也就是父消耗一定距离后,子再消耗,最后判断父消耗不)
     *
     * @param target       具体嵌套滑动的那个子类
     * @param dxConsumed   水平方向嵌套滑动的子控件滑动的距离(消耗的距离)
     * @param dyConsumed   垂直方向嵌套滑动的子控件滑动的距离(消耗的距离)
     * @param dxUnconsumed 水平方向嵌套滑动的子控件未滑动的距离(未消耗的距离)
     * @param dyUnconsumed 垂直方向嵌套滑动的子控件未滑动的距离(未消耗的距离)
     */
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {}

    /**
     * 嵌套滑动结束
     */
    public void onStopNestedScroll(View child) {}

    /**
     * 当子控件产生fling滑动时,判断父控件是否处拦截fling,如果父控件处理了fling,那子控件就没有办法处理fling了。
     *
     * @param target    具体嵌套滑动的那个子类
     * @param velocityX 水平方向上的速度 velocityX > 0  向左滑动,反之向右滑动
     * @param velocityY 竖直方向上的速度 velocityY > 0  向上滑动,反之向下滑动
     * @return 父控件是否拦截该fling
     */
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {}


    /**
     * 当父控件不拦截该fling,那么子控件会将fling传入父控件
     *
     * @param target    具体嵌套滑动的那个子类
     * @param velocityX 水平方向上的速度 velocityX > 0  向左滑动,反之向右滑动
     * @param velocityY 竖直方向上的速度 velocityY > 0  向上滑动,反之向下滑动
     * @param consumed  子控件是否可以消耗该fling,也可以说是子控件是否消耗掉了该fling
     * @return 父控件是否消耗了该fling
     */
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {}

    /**
     * 返回当前父控件嵌套滑动的方向,分为水平方向与,垂直方法,或者不变
     */
    public int getNestedScrollAxes() {}
NestedScrollingChild
/**
     * 开启一个嵌套滑动
     *
     * @param axes 支持的嵌套滑动方法,分为水平方向,竖直方向,或不指定
     * @return 如果返回true, 表示当前子控件已经找了一起嵌套滑动的view
     */
    public boolean startNestedScroll(int axes) {}

    /**
     * 在子控件滑动前,将事件分发给父控件,由父控件判断消耗多少
     *
     * @param dx             水平方向嵌套滑动的子控件想要变化的距离 dx<0 向右滑动 dx>0 向左滑动
     * @param dy             垂直方向嵌套滑动的子控件想要变化的距离 dy<0 向下滑动 dy>0 向上滑动
     * @param consumed       子控件传给父控件数组,用于存储父控件水平与竖直方向上消耗的距离,consumed[0] 水平消耗的距离,consumed[1] 垂直消耗的距离
     * @param offsetInWindow 子控件在当前window的偏移量
     * @return 如果返回true, 表示父控件已经消耗了
     */
    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow) {}


    /**
     * 当父控件消耗事件后,子控件处理后,又继续将事件分发给父控件,由父控件判断是否消耗剩下的距离。
     *
     * @param dxConsumed     水平方向嵌套滑动的子控件滑动的距离(消耗的距离)
     * @param dyConsumed     垂直方向嵌套滑动的子控件滑动的距离(消耗的距离)
     * @param dxUnconsumed   水平方向嵌套滑动的子控件未滑动的距离(未消耗的距离)
     * @param dyUnconsumed   垂直方向嵌套滑动的子控件未滑动的距离(未消耗的距离)
     * @param offsetInWindow 子控件在当前window的偏移量
     * @return 如果返回true, 表示父控件又继续消耗了
     */
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {}

    /**
     * 子控件停止嵌套滑动
     */
    public void stopNestedScroll() {}


    /**
     * 当子控件产生fling滑动时,判断父控件是否处拦截fling,如果父控件处理了fling,那子控件就没有办法处理fling了。
     *
     * @param velocityX 水平方向上的速度 velocityX > 0  向左滑动,反之向右滑动
     * @param velocityY 竖直方向上的速度 velocityY > 0  向上滑动,反之向下滑动
     * @return 如果返回true, 表示父控件拦截了fling
     */
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {}

    /**
     * 当父控件不拦截子控件的fling,那么子控件会调用该方法将fling,传给父控件进行处理
     *
     * @param velocityX 水平方向上的速度 velocityX > 0  向左滑动,反之向右滑动
     * @param velocityY 竖直方向上的速度 velocityY > 0  向上滑动,反之向下滑动
     * @param consumed  子控件是否可以消耗该fling,也可以说是子控件是否消耗掉了该fling
     * @return 父控件是否消耗了该fling
     */
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {}

    /**
     * 设置当前子控件是否支持嵌套滑动,如果不支持,那么父控件是不能够响应嵌套滑动的
     *
     * @param enabled true 支持
     */
    public void setNestedScrollingEnabled(boolean enabled) {}

    /**
     * 当前子控件是否支持嵌套滑动
     */
    public boolean isNestedScrollingEnabled() {}

    /**
     * 判断当前子控件是否拥有嵌套滑动的父控件
     */
    public boolean hasNestedScrollingParent() {}

其调用的相关的调用关系如下图所示,

1621853386(1).png

现在先看框部分的,后半部分将在下篇进行分析。

NestedScrollingChild2与NestedScrollingParent2这两个接口,主要是处理fling事件,子控件就能将fling传递给父控件,并且父控件处理了部分fling后,又可以将剩余的fling再传递给子控件。当子控件停止fling时,通知父控件fling结束了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容