嵌套滑动 - Behavior
2019-11-23 本文已影响0人
棍子哥丸子妹
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