《Android進階之光》Design Support Library常用控件(二):CoordinatorLayout

說起CoordinatorLayout,一直不是很明瞭,也沒正在用過,只是看到現在項目中有使用到。就跟着《Android進階之光》以及一篇博客CoordinatorLayout的使用如此簡單學習了。

CoordinatorLayout是協調者佈局,協調子view的。

通常用法是和Appbarlayout、CollapsingToolBarLayout結合使用。但是要理解深刻,必須先分開講。

先看一個圖:

這個效果是 拖動藍色方塊,旁邊的按鈕會隨之滑動:Y方向相同,X方向相反。

以前實現思路可能就是,在自定義藍色View重寫onTouchEvent,持有button的引用,根據手指活動的位置對button進行佈局。如果把button換成其他view又要持有其他view的引用,耦合度搞。  現在看下如何使用CoordinatorLayout來協調藍色View和button來實現這個效果。

CoordinatorLayout的使用核心是Behavior

Behavior就是你定製的行爲,例如上面的button隨着藍色view的移動,即 button 依賴 藍色view 而表現出在Behavior中定製的行爲。

怎麼定義Behavior呢?

1、繼承CoordinatorLayout.Behavior,實現layoutDependsOn、onDependentViewChanged兩個方法。相關說明在註釋中有寫到。

public class TestBehavior extends CoordinatorLayout.Behavior<Button> {

    /**
     * 屏幕寬度
     */
    private int mWidth;

    public TestBehavior() {
    }

    public TestBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        mWidth = displayMetrics.widthPixels;
    }

    /**
     * 判斷child的佈局是否依賴dependency
     * @param parent CoordinatorLayout
     * @param child 執行動作的CoordinatorLayout的子View,即設置這個behavior的view
     * @param dependency Child依賴的View,需要關心的view
     * @return 返回false表示child不依賴dependency,true表示依賴
     */
    @Override
    public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull Button child, @NonNull View dependency) {
        //如果dependency是MovingView的實例,說明它就是我們所需要的Dependency
        return dependency instanceof MovingView;
    }

    /**
     * 當dependency發生改變時(位置、寬高等),執行這個函數
     * @param parent
     * @param child
     * @param dependency
     * @return 返回true表示 child的位置或者是寬高 要發生改變,否則就返回false
     */
    @Override
    public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull Button child, @NonNull View dependency) {

        int left = dependency.getLeft();
        int top = dependency.getTop();

        //dependency移動時,child隨着dependency移動:豎直方向一致,水平方向反向移動
        child.layout(mWidth - left - child.getWidth(), top, mWidth - left, top + child.getHeight());

        return true;
    }
}

2、爲Button設置Behavior

<?xml version="1.0" encoding="utf-8"?><!--使用CoordinatorLayout-->
<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"
    tools:context=".module.home.BehaviorTestActivity">

    <!--隨手指滑動的view-->
    <com.hfy.demo01.common.customview.MovingView
        android:id="@+id/mv_test"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@color/colorPrimary" />

    <!--給Button設置定義好的layout_behavior-->
    <!--CoordinatorLayout的使用核心是Behavior,Behavior就是執行你定製的動作。-->
    <Button
        android:id="@+id/btn_test_behavior"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="test_behavior"
        android:textAllCaps="false"
        app:layout_behavior="com.hfy.demo01.module.home.TestBehavior" />

</android.support.design.widget.CoordinatorLayout>

以上。

 

附上滑動view的代碼:

public class MovingView extends View {

    /**
     * 手指按下的初始X座標
     */
    private int mLastX;

    /**
     * 手指按下的初始Y座標
     */
    private int mLastY;

    public MovingView(Context context) {
        super(context);
    }

    public MovingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MovingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //觸摸點相對view的座標。(滑動過程中,這個值不變)
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //滑動的距離 = 觸摸點滑動到的座標 - 開始觸摸的座標 (都是相對於view本身)
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;

                //所以View也要跟上這個滑動距離
                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
                break;
            case MotionEvent.ACTION_UP:
//                Toast.makeText(getContext(), "點了", Toast.LENGTH_SHORT).show();
                break;
            default:
                break;
        }
        return true;
    }
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章