Behavior是CoordinatorLayout的一個抽象內部類
public abstract static class Behavior<V extends View> {
public Behavior() {
}
public Behavior(Context context, AttributeSet attrs) {
}
...
}
泛型對應的就是監聽的view
自定義behavior有兩種情況
1.某個view監聽另一個view的狀態變化,例如大小、位置、顯示狀態等
- layoutDependsOn 方法
- onDependentViewChanged 方法
2.某個view監聽CoordinatorLayout里的滑動狀態
- onStartNestedScroll 方法
- onNestedPreScroll 方法
下面定義一個behavior ,實現一個view監控另一個view實現滑動
public class MyBehavior extends CoordinatorLayout.Behavior<View> {
public MyBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return super.layoutDependsOn(parent, child, dependency);
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
ViewCompat.offsetLeftAndRight();
return super.onDependentViewChanged(parent, child, dependency);
}
}
帶有兩個參數的這個構造必須重載,因為在CoordinatorLayout里利用反射去獲取這個Behavior的時候就是拿的這個構造。重兩個方法layoutDependsOn和onDependentViewChanged,這兩個方法的參數都是一樣的,第二個參數是我們設置這個Behavior的View,第三個是我們關心的那個View。如何知道關心的哪個呢?layoutDependsOn的返回值決定了一切!
比如一個TextView
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof TextView;
}
設置了關心誰,就是在該view狀態發生變化時我們的view要做出一些變化
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
child.setX(dependency.getX()+200);
child.setY(dependency.getY()+200);
child.setText(dependency.getX()+","+dependency.getY());
return true;
}
獲取兩個View的距離頂部值的差,然后讓child的位置進行移動
那么xml我么可以這樣寫
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:onclick="click"
android:id="@+id/button"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#57caa1"
android:gravity="center"
android:textColor="#fff"
android:layout_gravity="top|left"
android:text="啊哈"/>
<TextView
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#F26D7E"
android:gravity="center"
android:textColor="@android:color/white"
android:layout_gravity="top|right"
app:layout_behavior="com.emplme.MytBehavior"
android:text="555666"/>
</android.support.design.widget.CoordinatorLayout>
第二個textView就是我們的view設置了我們自定義的behavior
然后
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnTouchListener(new View.OnTouchListener() {
@Override public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
v.setX(event.getRawX()-v.getWidth()/2);
v.setY(event.getRawY()-v.getHeight()/2);
break;
}
return false;
}
});
}
接下來第二種情況
public class ScrollBehavior extends CoordinatorLayout.Behavior<View> {
public ScrollBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
}
@Override
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY) {
return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
}
}
onStartNestedScroll返回值表示要不要關心CoordinatorLayout滑動,那個方向的
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
當然我們這是Y軸方向的
onNestedPreScroll關于滑動的處理
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
int leftScrolled = target.getScrollY();
child.setScrollY(leftScrolled);
}
列子如下:
public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior<View> {
private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();
private boolean mIsAnimatingOut = false;
public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
super();
}
@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
@Override
public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
if (dy>0 && !this.mIsAnimatingOut && child.getVisibility() == View.VISIBLE) {
animateOut(child);
} else if (dy < 0 && child.getVisibility() != View.VISIBLE) {
animateIn(child);
}
}
private void animateOut(final View button) {
ViewCompat.animate(button).translationY(button.getHeight() + getMarginBottom(button)).setInterpolator(INTERPOLATOR).withLayer()
.setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
ScrollAwareFABBehavior.this.mIsAnimatingOut = true;
}
@Override
public void onAnimationEnd(View view) {
ScrollAwareFABBehavior.this.mIsAnimatingOut = false;
view.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationCancel(View view) {
ScrollAwareFABBehavior.this.mIsAnimatingOut = false;
}
}).start();
}
private void animateIn(View button) {
button.setVisibility(View.VISIBLE);
ViewCompat.animate(button).translationY(0)
.setInterpolator(INTERPOLATOR).withLayer().setListener(null)
.start();
}
private int getMarginBottom(View v) {
int marginBottom = 0;
final ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
marginBottom = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin;
}
return marginBottom;
}
}
結尾在放上一些自定義behavior的炫酷效果
CoordinatorLayout 自定義Behavior并不難,由簡到難手把手帶你擼三款
CoordinatorLayout與滾動的處理--基礎
自定義CoordinatorLayout的Behavior實現知乎和簡書快速返回效果
CoordinatorLayout高級用法-自定義Behavior