嵌套滑动 - Behavior

CoordinatorLayout
类似于一个FrameLayout 的容器,在嵌套滑动中有两个功能:
1.作为嵌套滑动顶层布局
2.作为与一个或者多个直接子view进行交互的特定容器

通过给 CoordinatorLayout 的直接子view设置 Behaviors 属性,实现子view之间进行不同的滑动交互以及布局修改。实现子view之间执行移动或者动画的,实现其他子View跟随动作。

Behavior
这个CoordinatorLayout类内部的 抽象类,定义了子试图的交互行为。这些互动可能包括拖曳,滑动,投掷,或任何其他手势。主要的Api如下:
CoordinatorLayout.Behavior

/**
     * 是否给应用了Behavior的View,指定一个观察的布局
     * 当布局发生变化的时候
     * 确定所提供的子视图是否有另一个特定的同级视图作为布局依赖项。
     * 注意:本身的View会重新布局
     *
     * @param parent 顶层嵌套布局
     * @param child 绑定behavior的View(观察者,就是TextView本身)
     * @param dependency 被观察的view(被观察者,就是同级别的其他子视图)
     * @return 这里可以检查自己需要观察的试图,是返回true,否则返回false
     */
    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        Log.i(TAG,"layoutDependsOn child " + child.getClass().getSimpleName()
                + "  dependency " + dependency.getClass().getSimpleName());
        // 这里检查被观察者(TexView观察的是滑动NestedScrollView)
        return dependency instanceof NestedScrollView;
    }


    /**
     * 是否响应子程序依赖视图(被观察者)中的更改
     * 每当依赖视图在标准布局流之外的大小或位置发生变化时,都会调用此方法
     *
     * @param parent 顶层嵌套布局
     * @param child 绑定behavior的View(观察者,就是TextView本身)
     * @param dependency 被观察的view(被观察者,就是同级别的其他子视图)
     * @return true 响应了被观察者的变化,false没有响应
     */
    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        Log.i(TAG,"onDependentViewChanged child " + child.getClass().getSimpleName()
                + "  dependency " + dependency.getClass().getSimpleName());
        //一开始  等于0
        if (deltaY == 0) {
            //初始化两者之间的距离
            deltaY = dependency.getY() - child.getHeight();
        }
        Log.i("DN deltaY------------>",deltaY+"------------");
        //被观察者View的Y坐标 - 观察者的高度  得到两者之间剩余的距离
        float dy = dependency.getY() - child.getHeight();
        //如果距离小于0  就赋值0  如果距离大于等于0  就把剩余距离赋值给它
        dy = dy < 0 ? 0 : dy;
        //计算Y轴每次偏移的距离
        float y = -(dy / deltaY) * child.getHeight();
        Log.i("DN-------------->",y+"------------");
        //设置Y轴的偏移参数
        child.setTranslationY(y);
        return false;
    }

    /**
     *  当coordinatorLayout 的子View试图开始嵌套滑动的时候被调用
     *  任何与协调员Layout的任何直接子级相关联的行为都可能响应此事件并返回TRUE,
     *  以指示协调员Layout应该充当此滚动条的嵌套滚动父级。
     *  只有从此方法返回true的行为才会接收后续嵌套滚动事件。
     *
     * @param coordinatorLayout 顶层嵌套布局
     * @param child 绑定behavior的View(观察者,就是TextView本身)
     * @param directTargetChild 该子视图是或包含嵌套滚动操作的目标
     * @param target View启动嵌套滚动的协调员Layout的后代视图
     * @param nestedScrollAxes 嵌套滑动滑动方向,横向或者竖向
     * @param type 导致此滚动事件的输入类型
     * @return 如果行为希望接受此嵌套滚动,则为true。
     */
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild,
                                       View target, int nestedScrollAxes, int type) {
        Log.i(TAG,"onStartNestedScroll type " + type);
        return true;
    }


    /**
     * 当正在进行的嵌套滚动即将更新时,在目标消耗任何滚动距离之前调用
     * 在nested scroll child 消费掉自己的滚动距离之前,嵌套滚动每次被nested scroll child
     * 更新都会调用onNestedPreScroll。注意有个重要的参数consumed,可以修改这个数组表示你消费
     * 了多少距离。假设用户滑动了100px,child 做了90px 的位移,你需要把 consumed[1]的值改成90,
     * 这样coordinatorLayout就能知道只处理剩下的10px的滚动。
     *
     * @param coordinatorLayout 顶层嵌套布局
     * @param child 绑定behavior的View(观察者,就是TextView本身)
     * @param target View启动嵌套滚动的协调员Layout的后代视图
     * @param dx  用户试图滚动的原始水平像素数
     * @param dy  用户试图滚动的原始垂直像素数
     * @param consumed 输出参数。消费[0]应设置为消耗的dx的距离,消费[1]应设置为所消费的dy的距离。
     */
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed, int type) {
        Log.i(TAG,"onNestedPreScroll dx " + dx
                + "  dy " + dy);
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed,type);
    }



    /**
     * 当正在进行的嵌套滚动更新并且目标已滚动或试图滚动时调用。
     *
     * @param coordinatorLayout 顶层嵌套布局
     * @param child 绑定behavior的View
     * @param target 被观察的view(被观察者,就是同级别的其他子视图)
     * @param dxConsumed target 已经消费的x方向的距离
     * @param dyConsumed target 已经消费的y方向的距离
     * @param dxUnconsumed x 方向剩下的滚动距离
     * @param dyUnconsumed y 方向剩下的滚动距离
     */
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed,
                               int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        Log.i(TAG,"onNestedScroll child " + child.getClass().getSimpleName()
                + "  dependency " + target.getClass().getSimpleName());
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,type);
    }

    /**
     *  嵌套滚动结束时被调用,这是一个清除滚动状态等的好时机。
     *
     * @param coordinatorLayout 顶层嵌套布局
     * @param child 绑定behavior的View(观察者,就是TextView本身)
     * @param target 被观察的view(被观察者,就是同级别的其他子视图)
     */
    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int type) {
        Log.i(TAG,"onStopNestedScroll child " + child.getClass().getSimpleName()
                + "  dependency " + target.getClass().getSimpleName());
        super.onStopNestedScroll(coordinatorLayout, child, target,type);
    }

    /**
     * onStartNestedScroll返回true才会触发这个方法,接受滚动处理后回调,可以在这个
     * 方法里做一些准备工作,如一些状态的重置等。
     *
     * @param coordinatorLayout 顶层嵌套布局
     * @param child 绑定behavior的View(观察者,就是TextView本身)
     * @param directTargetChild 该子视图是或包含嵌套滚动操作的目标
     * @param target 被观察的view(被观察者,就是同级别的其他子视图)
     * @param nestedScrollAxes 方向
     * @param type 导致此滚动事件的输入类型
     */
    @Override
    public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, View child, View directTargetChild,
                                       View target, int nestedScrollAxes,int type) {
        Log.i(TAG,"onNestedScrollAccepted child " + child.getClass().getSimpleName()
                + "  dependency " + target.getClass().getSimpleName());
        super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes,type);
    }

    /**
     * 用户松开手指并且会发生惯性动作之前调用,参数提供了速度信息,可以根据这些速度信息
     * 决定最终状态,比如滚动Header,是让Header处于展开状态还是折叠状态。返回true 表
     * 示消费了fling.
     *
     * @param coordinatorLayout 顶层嵌套布局
     * @param child 绑定behavior的View(观察者,就是TextView本身)
     * @param target 被观察的view(被观察者,就是同级别的其他子视图)
     * @param velocityX x 方向的速度
     * @param velocityY y 方向的速度
     * @return true 行为消耗了,否则没有
     */
    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target,
                                    float velocityX, float velocityY) {
        Log.i(TAG,"onNestedPreFling child " + child.getClass().getSimpleName()
                + "  dependency " + target.getClass().getSimpleName());
        return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
    }



    //可以重写这个方法对子View 进行重新布局
    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
        Log.i(TAG,"onLayoutChild child " + child.getClass().getSimpleName());
        return super.onLayoutChild(parent, child, layoutDirection);
    }

上面的代码用也用 TextView作为观察者,自定义它的Behavior的行为,跟随 NestedScrollView 滑动
https://github.com/liuguangsen/HightUi/blob/master/app/src/main/java/com/liugs/materialdesigntest/behavior/BehaviorTest.java

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

推荐阅读更多精彩内容