Behavior 是 CoordinatorLayout爲其 子視圖 提供的一種交互行爲插件。
它實現了用戶能夠操做子視圖的一種或多種交互行爲,包括包括拖拽,Fling(滑翔)或任何其餘手勢。java
自定義Behavior,這裏分爲兩類:swift
layoutDependsOn
和onDependentViewChanged
做爲一組。Dependent機制最多見的案例就是 FloatingActionButton
和 SnackBar
的交互行爲。如圖
onStartNestedScroll
和onNestedScroll
做爲一組。Nested機制要求 CoordinatorLayout
包含了一個實現了 NestedScrollingChild
接口的滾動視圖控件,好比v7包中的 RecyclerView
,設置 Behavior
屬性的Child View
會隨着這個控件的滾動而發生變化。如圖以下只標註了Behavior
部分方法。開發者能夠根據自身業務需求有選擇的複寫。app
部分方法ide
/** * @param parent * @param child 給定的View,即應用了layout_behavior的View * @param dependency 任何與child同級的View * @return 若是返回true,那麼parent將作兩件事: * 1.將忽略View的順序,老是先去佈局dependency,以後佈局child。 * 2.當dependency視圖的佈局或位置發生改變時,調用onDependentViewChanged方法。 */
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
//判斷dependency是不是須要的依賴項,若是是,則返回true
return false;
}複製代碼
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
//處理child的位置或大小,並返回true
return true;
}複製代碼
/** * @param coordinatorLayout * @param child 關聯Behavior的CoordinatorLayout的子View * @param directTargetChild CoordinatorLayout的子View或包含嵌套滾動操做的View。好比RecycleView外層的RelativeLayout * @param target 嵌套滾動的View * @param nestedScrollAxes 嵌套滾動的座標軸。SCROLL_AXIS_HORIZONTAL, SCROLL_AXIS_VERTICAL * @return */
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return false;
}複製代碼
/** * * @param coordinatorLayout * @param child * @param target * @param dxConsumed 水平方向滾動增量, * @param dyConsumed 垂直方向滾動增量,若是大於0,手指上滑中;若是小於0,手指下滑中。 * @param dxUnconsumed 同dyUnconsumed描述 * @param dyUnconsumed 正常狀況下,始終爲0,當View處於最頂部或最底部,用戶仍然強制下滑或上滑時,dy則不爲0 */
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
if (dyConsumed > 0 && dyUnconsumed == 0) {
System.out.println("上滑中。。。");
}
if (dyConsumed == 0 && dyUnconsumed > 0) {
System.out.println("到邊界了還在上滑。。。");
}
if (dyConsumed < 0 && dyUnconsumed == 0) {
System.out.println("下滑中。。。");
}
if (dyConsumed == 0 && dyUnconsumed < 0) {
System.out.println("到邊界了,還在下滑。。。");
}
}複製代碼
經過查看CoordinatorLayout
源碼能夠知道,它有一個內部類LayoutParams
,用於存儲CoordinatorLayout
的全部子View
佈局參數,其中Behavior
也是LayoutParams
的一個屬性值。所以和文章開始的描述保持了一致,Behavior
只能設置到CoordinatorLayout
的子View
上。函數
/** * Parameters describing the desired layout for a child of a {@link CoordinatorLayout}. */
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
/** * A {@link Behavior} that the child view should obey. */
Behavior mBehavior;
//省略n多代碼
}複製代碼
app:layout_behavior="com.yolo.myapplication.MyBehavior"
app:layout_behavior="@string/appbar_scrolling_view_behavior"佈局
在LayoutParams構造方法中,調用了parseBehavior(context, attrs, a.getString( R.styleable.CoordinatorLayout_Layout_layout_behavior))
方法。判斷名稱,而後經過反射機制實例化Behavior
。從而回調Behaivor
的其餘方法。ui
注意:在自定義 Behavior
時,必定要重寫第二個帶參數的構造函數,不然這個 Behavior
是不會起做用的。this
static Behavior parseBehavior(Context context, AttributeSet attrs, String name) {
if (TextUtils.isEmpty(name)) {
return null;
}
final String fullName;
if (name.startsWith(".")) {
//若是behavior的值以 . 開頭,則自動補全包名信息
// Relative to the app package. Prepend the app package name.
fullName = context.getPackageName() + name;
} else if (name.indexOf('.') >= 0) {
// Fully qualified package name.
fullName = name;
} else {
// Assume stock behavior in this package (if we have one)
fullName = !TextUtils.isEmpty(WIDGET_PACKAGE_NAME)
? (WIDGET_PACKAGE_NAME + '.' + name)
: name;
}
try {
Map<String, Constructor<Behavior>> constructors = sConstructors.get();
if (constructors == null) {
constructors = new HashMap<>();
sConstructors.set(constructors);
}
Constructor<Behavior> c = constructors.get(fullName);
if (c == null) {
//經過反射實例化Behavior
final Class<Behavior> clazz = (Class<Behavior>) Class.forName(fullName, true,
context.getClassLoader());
c = clazz.getConstructor(CONSTRUCTOR_PARAMS);
c.setAccessible(true);
constructors.put(fullName, c);
}
return c.newInstance(context, attrs);
} catch (Exception e) {
throw new RuntimeException("Could not inflate Behavior subclass " + fullName, e);
}
}複製代碼