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