NestedScrolling 0

Why

Android事件分发机制一般情况下能满足大部分情况下View事件处理,其中的关键点就是事件拦截和事件上传,具体的详情这里不做展开。假设现在有这样一种场景,ViewGroup有且仅有一个Child View,�
要求是Child消费down事件、ViewGroup消费move事件,这种情况就不太好处理,原因是Child消费down事件后,后续的move、up和cancel的onTouchEvent返回false, 事件都会发送到Child, ViewGroup不会有机会处理。可以看出down事件是否消费很关键,根据默认的事件分发机制似乎不能完成这里的要求,好在google提供了design(Android L版本提出), design库其中的一个重要特性就是嵌套滑动机制。�

What

嵌套滑动可以简单的理解成父(ViewGroup)和子(View或者ViewGroup)共同处理move事件,流程是这样的:�子View先将滑动事件交给父View处理,�父View根据情况消耗全部或者部分move偏移量,子View再消耗剩余的move偏移量,最后子View再通知父View scroll消耗的情况,父View根据这个需求再进行滑动,整个过程的顺序如下:

0,父View先处理scroll
1,子View再处理scroll
2,父View再处理scroll
3,子View再处理scroll

元素

主要接口有2个,分别是 NestedScrollingParent
NestedScrollingChild
,父 View 需要实现 NestedScrollingParent接口,而子 View 需要实现 NestedScrollingChild接口。

NestedScrollingChild接口的源码如下:

public interface NestedScrollingChild {
    //设置是否开启嵌套滑动功能
    public void setNestedScrollingEnabled(boolean enabled);
    public boolean isNestedScrollingEnabled();
    //开始一个新的嵌套滑动,参数指定横向或者纵向
    public boolean startNestedScroll(int axes);
    //结束一个已经开始的嵌套
    public void stopNestedScroll();
    //是否有对应的parent配合处理滑动事件
    public boolean hasNestedScrollingParent();
    //scroll的预处理过程,对应上图的0和1
    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);
    //scroll的后处理过程,对应上图的2和3
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
            int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);
    //fling和scroll和类似
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);
}

NestedScrollingParent接口的源码如下:

public interface NestedScrollingParent {
    //是否接受子View的嵌套滑动
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);
    //成功后的回调
    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);
    //结束后的回调
    public void onStopNestedScroll(View target);
    //预处理过程,对应上图的0
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);
    //后处理过程,对应上图的2
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
            int dxUnconsumed, int dyUnconsumed);
    //fling和scroll和类似
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);
    public boolean onNestedPreFling(View target, float velocityX, float velocityY);
    //横向还是纵向
    public int getNestedScrollAxes();
}

google还提供了2个辅助类来帮助实现整个过程,分别是NestedScrollingChildHelperNestedScrollingParentHelper,从名字可以看出分别作用的对象是Child和Parent。

比如Child的用法如下:

// NestedScrollingChild

    @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        getScrollingChildHelper().setNestedScrollingEnabled(enabled);
    }

    @Override
    public boolean isNestedScrollingEnabled() {
        return getScrollingChildHelper().isNestedScrollingEnabled();
    }

    @Override
    public boolean startNestedScroll(int axes) {
        return getScrollingChildHelper().startNestedScroll(axes);
    }

    @Override
    public void stopNestedScroll() {
        getScrollingChildHelper().stopNestedScroll();
    }

    @Override
    public boolean hasNestedScrollingParent() {
        return getScrollingChildHelper().hasNestedScrollingParent();
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
            int dyUnconsumed, int[] offsetInWindow) {
        return getScrollingChildHelper().dispatchNestedScroll(dxConsumed, dyConsumed,
                dxUnconsumed, dyUnconsumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
        return getScrollingChildHelper().dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        return getScrollingChildHelper().dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        return getScrollingChildHelper().dispatchNestedPreFling(velocityX, velocityY);
    }

都是直接的调用helper的方法,可以看出google为了减少开发者的学习和开发成本费了很多心思。Parent的helper相比于Child提供的方法就不是那么多了,主要的逻辑主要靠开发者自己实现。

流程

Child Parent
startNestedScroll onStartNestedScroll、onNestedScrollAccepted
dispatchNestedPreScroll onNestedPreScroll
dispatchNestedScroll onNestedScroll
stopNestedScroll onStopNestedScroll

可以看出是一一对应的关系,整个过程是Child主导,Parent配合完成,用文字说明一下整个过程:

1. 准备过程

Child发起一个嵌套滑动处理,调用startNestedScroll.
Parent回调onStartNestedScroll说明收到了来自Child的请求,根据情况决定是否接受Child请求,通过返回值告诉Child结果。
Parent如果接受Child的请求还会回调onNestedScrollAccepted。

2. 处理过程

每次滑动前,Child 先询问 Parent 是否需要滑动,即 dispatchNestedPreScroll(),这就回调到 Parent 的 onNestedPreScroll(),Parent 可以在这个回调中“劫持”掉 Child 的滑动,也就是先于 Child 滑动。

Child 滑动以后,会调用 onNestedScroll(),回调到 Parent 的 onNestedScroll(),这里就是 Child 滑动后,剩下的给 Parent 处理,也就是 后于 Child 滑动。

3. 结束过程

Child调用stopNestedScroll发起一个结束请求,Parent回调回调onStopNestedScroll处理相关逻辑,比如重置参数等待下次滑动请求

版本兼容

虽然是Api21版本才提出的,google也提供了兼容方案,相关接口再android.support.v4包中

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

推荐阅读更多精彩内容