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