CoordinatorLayout 布局系列 Behavior 的自定义

来源:互联网 发布:java实施是做什么的 编辑:程序博客网 时间:2024/05/16 08:16
CoordinatorLayout.Behavior 源码常见方法解析
    /**     * 布局试图进行嵌套滚动     * @param coordinatorLayout  当前的 CoordinatorLayout     * @param child              设置 Behavior 的View     * @param directTargetChild 观察的布局(依赖的布局)     * @param target (暂时不知道具体是什么)     * @param axes  滚动的方式     *                         {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},     *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL}     * @param type 事件类型     * @return 如果希望接受这个嵌套滚动的行为  返回 true     * (该方法,一定要按照自己的需求返回true,该方法决定了当前控件是否能接收到其内部View(非并非是直接子View)滑动时的参数;假设你只涉及到纵向滑动,这里可以根据nestedScrollAxes这个参数,进行纵向判断。)     */    @Override    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {        KLog.e("onStartNestedScroll");         return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;    }    /**     * 该方法的会传入内部View移动的dx,dy,如果你需要消耗一定的dx,dy,就通过最后一个参数consumed进行指定,例如我要消耗一半的dy,就可以写consumed[1]=dy/2     */    @Override    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {        KLog.e("onNestedPreScroll");        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);        int leftScrolled = target.getScrollY();        child.setScrollY(leftScrolled);    }    /**    * 你可以捕获对内部View的fling事件,如果return true则表示拦截掉内部View的事件。    * (什么是:fling? 挡我们滑动时,松开时,ScrollView会滑动一会)    */    @Override    public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View target, float velocityX, float velocityY) {        KLog.e("onNestedPreFling");        ((NestedScrollView) child).fling((int)velocityY);        return true;    }    /**     * 确定提供子视图还有另一个特定的兄弟视图布局的依赖     * @param parent     当前的 CoordinatorLayout     * @param child      设置 Behavior 的View     * @param dependency 观察的布局(依赖的布局)     * @return 如果你关心这个布局 就 返回 true  否则返回 false     * @see #onDependentViewChanged(CoordinatorLayout, android.view.View, android.view.View)     */    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {    }    /**     * 调用此方法时依赖视图改变大小或位置之外的标准布局流。     * 一个行为可能使用此方法来适当地更新子视图     * @param parent     当前的 CoordinatorLayout     * @param child      操作的子View     * @param dependency 依赖的观察的View发生了改变     * @return true 如果行为改变子视图的大小或位置,     */    @Override    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {    }    /**     * 这个方法可以用来执行自定义或修改布局的孩子视图的默认布局行为。     * 行为的实现可以委托标准协调布局测量行为通过调用     * {@link CoordinatorLayout#onLayoutChild(android.view.View, int)     * @param parent the parent CoordinatorLayout     * @param child child view to lay out     * @param layoutDirection the resolved layout direction for the CoordinatorLayout, such as     *                        {@link ViewCompat#LAYOUT_DIRECTION_LTR} or     *                        {@link ViewCompat#LAYOUT_DIRECTION_RTL}.     * @return true 是否重新设置了默认布局行为     */    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {        return false;    }

一般的 CoordinatorLayout 在使用时配合ScrollView时,都需要在Xml加入以下代码

<android.support.v4.widget.NestedScrollView    app:layout_behavior="@string/appbar_scrolling_view_behavior">    ....内容区域</android.support.v4.widget.NestedScrollView

点击进去 我们发现其实 使用的就是类
android.support.design.widget.AppBarLayout$ScrollingViewBehavior

那么我们来做一个小效果

这里写图片描述

xml布局代码

关键就是这句话,指定我们自己自定义的类
app:layout_behavior=”.DependentBehavior”

<android.support.design.widget.CoordinatorLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:fitsSystemWindows="true">    <TextView        android:id="@+id/depentent"        android:layout_width="100dp"        android:layout_height="100dp"        android:background="@android:color/holo_red_dark"        android:gravity="center"        android:layout_gravity="top|left"        android:text="我移动"/>    <TextView        android:layout_width="100dp"        android:layout_height="100dp"        android:gravity="center"        android:background="@android:color/holo_orange_dark"        android:layout_gravity="top|right"        app:layout_behavior=".coordinator.DependentBehavior"        android:text="跟着移动"/></android.support.design.widget.CoordinatorLayout>

DependentBehavior的代码

public class DependentBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {    public DependentBehavior(Context context, AttributeSet attrs) {        super(context, attrs);    }    /**     * 确定提供子视图还有另一个特定的兄弟视图布局的依赖     * @param parent     当前的 CoordinatorLayout     * @param child      设置 Behavior 的View     * @param dependency 观察的布局(依赖的布局)     * @return 如果你关心这个布局 就 返回 true  否则返回 false     * @see #onDependentViewChanged(CoordinatorLayout, android.view.View, android.view.View)     */    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {        return dependency instanceof TextView;    }    /**     * 调用此方法时依赖视图改变大小或位置之外的标准布局流。     * 一个行为可能使用此方法来适当地更新子视图     * @param parent     当前的 CoordinatorLayout     * @param child      操作的子View     * @param dependency 依赖的观察的View发生了改变     * @return true 如果行为改变子视图的大小或位置,     */    @Override    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {        int offset = dependency.getTop() - child.getTop();        ViewCompat.offsetTopAndBottom(child, offset);        return true;    }}

我们设置监听 然红色的 TextView 随着鼠标移动

 mTvDepentent.setOnTouchListener(new View.OnTouchListener() {     private float mLastY = -1;     @Override     public boolean onTouch(View v, MotionEvent ev) {         if (mLastY == -1) {             mLastY = ev.getRawY();         }         switch (ev.getAction()) {             case MotionEvent.ACTION_DOWN:                 KLog.e("按下");                 mLastY = ev.getRawY();                 break;             case MotionEvent.ACTION_MOVE:                 KLog.e("移动");                 final float deltaY = ev.getRawY() - mLastY;                 //移动自身                 ViewCompat.offsetTopAndBottom(v, (int) deltaY);                 mLastY = ev.getRawY();                 break;             default:                 break;         }         return true;     } });