CoordinatorLayout中的Behavior主要用来实现控件之间的交互以及滑动交互。常见的Behavior有"@string/appbar_scrolling_view_hehavior" 以及 "@string/bottom_sheet_behavior" ,这两个是Design库自带的Behavior。我们自己也可以根据需要自定义Behavior,来实现漂亮的交互。
自定义Behavior可以分为两类,一类是定义控件监听CoordinatorLayout的滑动状态;一类是定义控件监听另一个控件的状态变化。
要自定义Behavior首先继承CoordinatorLayout.Behavior<V extends View>类,并实现构造方法。如下:
public class FootBehavior extends CoordinatorLayout.Behavior<View> {
public FootBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
然后根据需要重写相应的方法。
1. 监听CoordinatorLayout的滑动状态
要监听CoordinatorLayout的滑动状态,主要注意两个方法:onStartNestedScroll() 和 onNestedPreScroll() 。
/**
* 当CoordinatorLayout开始滑动时会调用这个方法,任意与CoordinatorLayout通过behavior关联的控件都要响应此方法并返回true
* 如果返回false,控件将不会响应CoordinatorLayout的滑动事件。
* @param coordinatorLayout
* @param child 与CoordinatorLayout通过behavior关联的控件
* @param directTargetChild
* @param target
* @param nestedScrollAxes 滑动方向,ViewCompat.SCROLL_AXIS_VERTICAL表示纵向滑动
* ViewCompat.SCROLL_AXIS_HORIZONTAL表示横向滑动
* @return
*/
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
//响应CoordinatorLayout的纵向滑动
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
/**
* CoordinatorLayout滑动时调用此方法
* @param coordinatorLayout
* @param child 与CoordinatorLayout通过behavior关联的子控件
* @param target
* @param dx 手指水平方向滑动的距离,左滑dx>0 右滑dx<0
* @param dy 手指竖直方法滑动的距离,上滑dy>0 下滑dy<0
* @param consumed 实际已滑动的距离,consumed[0]表示水平距离,consumed[1]表示竖直距离;
* 实际已滑动的距离总是小于或等于手指滑动的距离
*/
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
if(dy>MIN_SCROLL_DISTANCE && isVisible && !isAnimating){ //如果向上滑动,则隐藏底部控件
hideBottomView(child);
}else if(dy<-MIN_SCROLL_DISTANCE && !isVisible && !isAnimating){ //如果向下滑动,则显示底部控件
showBottomView(child);
}
}
这里我在CoordinatorLayout底部放了一个布局,希望CoordinatorLayout向上滑动的时候,底部布局隐藏起来;当CoordinatorLayout向下滑动的时候,底部布局显示出来。其中MIN_SCROLL_DISTANCE是自定义的一个常量,避免响应距离过小的滑动。isVisible用来标识当前底部布局的显示状态,还有isAnimating就不说了,文章最后将给出完整的代码。
2. 一个控件监听另一个控件的状态变化
一个控件监听另一个控件的状态变化,实际上就是要将这两个控件关联起来,当一个控件变动时,另一个控件也发生状态变化。这里主要也涉及到两个方法:layoutDependsOn() 以及 onDependentViewChanged() 。
/**
* 使一个控件与目标控件关联,如果要响应目标控件的变化,就返回true,否则返回false
* @param parent
* @param child 子控件
* @param dependency 被关联的目标控件,可以通过类型或者id来确定目标控件
* @return
*/
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
//return dependency instanceof Button;
return dependency.getId() == R.id.button;
}
/**
* 当目标控件状态发生状态变化时(比如位置和大小),会调用此方法
* @param parent
* @param child
* @param dependency
* @return
*/
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
//子控件的位置随着目标控件位置变化
child.setX(dependency.getX());
child.setY(dependency.getY() + dependency.getHeight() + 30);
return true;
}
自定义Behavior完成之后,就可以愉快地使用了:
<FrameLayout
app:layout_behavior=".FootBehavior"
android:layout_gravity="bottom"
android:background="@color/colorPrimary"
android:padding="15dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="自定义Behavior"
android:textColor="@android:color/white"
android:textSize="17sp"
android:layout_gravity="center"/>
</FrameLayout>
要查看完整代码点这里: TestBehavior @github