Behavior
Behavior 只有用在 CoordinatorLayout 的直接子 View 上才有效,他是 CoordinatorLayout 滚动事件的一系列回调。
自定义 Behavior 继承哪个类?
我们找到 CoordinatorLayout.Behavior 类后ctrl+h(as快捷键)发现有很多实现类,现在要实现的是 Fab 按钮的隐藏和显示,仔细寻找后发现在众多实现类中有一个 FloatingActionButton.Behavior ,他就是要继承的实现类。
自定义 Behavior 的实现
首先要继承FloatingActionButton.Behavior
public class MyBehavior extends FloatingActionButton.Behavior {
public MyBehavior(Context context, AttributeSet attrs) {
super();
}
}
这里有个重要的地方:自定义 Behavior 继承 FloatingActionButton.Behavior 之后要重写他有两个参数的构造方法,这是因为 Behavior 是 CoordinatorLayout 的内部类, CoordnatorLayout 是通过反射来从布局文件里面我们定义的 Behavior 属性创建 Behavior 的,创建时调用的构造方法就是那个带两个参数的构造方法。
然后实现里面重要的三个方法
// 页面开始滑动。
boolean onStartNestedScroll(CoordinatorLayout l, FloatingActionButton c, View directTargetChild, View v, int nestedScrollAxes);
// 页面正在滑动。
void onNestedScroll(CoordinatorLayout l, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed);
// 页面停止滑动
onStopNestedScroll();
onStartNestedScroll
当CoordinatorLayout里的滚动控件开始滚动的时候被调用,这个方法的最后一个参数表示当前页面的滚动方向是横向还是垂直的,现在要监听的是垂直方向的滚动,故判断这个值是否是ViewCompat.SCROLL_AXIS_VERTICAL,如果是则返回true,当前滚动的方向是我们需要监听的
boolean onStartNestedScroll(CoordinatorLayout l, FloatingActionButton c, View directTargetChild, View v, int nestedScrollAxes){
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
onNestedScroll
页面滚动时被调用(手指触摸屏幕开始移动时,只要手指移动就会调用,当然,这取决于onStartNestedScroll的返回值,比如手指在横向滑动,但是onStartNestedScroll返回false,那么这个方法不会被调用,只有当onStartNestedScroll返回true这个方法才会被调用,而onStartNestedScroll的返回值取决于你需要监听的方向),我们就在这个方法中实现Fab的显示/隐藏,这个方法接收七个参数,前三个参数不用介绍了,重点介绍后面四个参数
- int dxConsumed
- 当页面在横向方向有滑动的时候(不是手指的滑动,是页面上的像素点在x方向发生的变化),这个值就会变化。比如当页面向右滑动(x的正方向),滑动多少个点这个值就是多少
- int dxUnconsumed
- 页面滑动到顶或滑动到底手指还在滑动,这个值就会变化,当页面滑动到底手指还在上拉,这个值就会出现负值,值的大小取决于滑动到底后再向上拉的长度
dyConsumed和dyUnconsumed同上面两个道理相同,只是用于y轴(垂直方向)。
我们现在要实现的是页面向上滚动时Fab隐藏,页面向下滚动时Fab显示。所以我们需要用到的是dyConsumed
和dyUnconsumed
这两个参数
public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
//页面向上滑动像素数大于0 || 拉到底还在向上拉 && 退出动画是否正在执行 && FAB按钮当前显示中
if ((dyConsumed > 0 || dyUnconsumed > 0) && !isAnimatingOut && child.getVisibility() == View.VISIBLE) {
//隐藏Fab
child.hide();
} else if ((dyConsumed < 0 || dyUnconsumed < 0) && child.getVisibility() != View.VISIBLE) {
//显示Fab按钮
child.show();
}
}
在这段代码中我们通过判断界面的滚动和当前Fab的显示隐藏状态来做相应的操作,在这里Fab有自己的显示隐藏功能,如果是其他View需要自己写动画相关的代码。
onStopNestedScroll
Fab的显示和隐藏的动画已经在 onNestedScroll 方法中实现了,所以这个方法在这里不再赘述。
最后
到这里,一个自定义的用于Fab按钮的Behavior就写完了。
只需要在xml代码中给Fab按钮写如下属性,即可使用
<android.support.design.widget.FloatingActionButton
......
app:layout_behavior="包名.MyBehavior" />
当然,Fab按钮的父容器得是CoordinatorLayout