Android 5.0新控件 CoordinatorLayout | 協調佈局 介紹及使用詳情

Android 5.0新控件 CoordinatorLayout | 協調佈局 介紹及使用詳情

extends ViewGroup

implements NestedScrollingParent

CoordinatorLayout is a super-powered FrameLayout

CoordinatorLayout is intended for two primary use cases:

1.As a top-level application decor or chrome layout

2.As a container for a specific interaction with one or more child views

Google官方對這個控件的大概意思這是一個加強型的幀佈局,主要有兩個兩個用例方面:

1.作爲頂層佈局

2.調度協調子佈局

那麼到底CoordinatorLayout有什麼功能呢!說得再好不如來張圖

使用方法

CoordinatorLayout來自design兼容包,使用需要添加依賴。android studio 添加依賴如下:

dependencies {
    compile ‘com.android.support:design:24.2.0‘
}

1.首先,XML中添加布局文件


    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/colorTheme"
                android:contentInsetStart="0dp"
                app:layout_scrollFlags="scroll|enterAlways|snap">

                <ImageView
                    android:id="@+id/imageview_back"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingBottom="20dp"
                    android:paddingLeft="5dp"
                    android:paddingRight="20dp"
                    android:paddingTop="20dp"
                    android:src="@drawable/back"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="CoordinatorLayout"
                    android:textColor="@android:color/white"/>

            </android.support.v7.widget.Toolbar>
        </android.support.design.widget.AppBarLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
    </android.support.design.widget.CoordinatorLayout>

2.僅僅這些佈局文件,就可以實現當RecyclerView向上滑動時Toolbar隱藏,向下滑動時Toolbar顯示,下面來介紹下其屬性

CoordinatorLayout一般直接作爲根佈局使用,否則會有一些功能失效

CoordinatorLayout的使用核心是Behavior,Behavior就是執行你定製的動作。在講Behavior之前必須先理解兩個概念:Child和Dependency,什麼意思呢?Child當然是子View的意思了,是誰的子View呢,當然是CoordinatorLayout的子View;其實Child是指要執行動作的CoordinatorLayout的子View。而Dependency是指Child依賴的View。比如上面的gif圖中,RecyclerView就是Child,Toolbar就是Dependency,因爲Toolbar的動作是依賴於RecyclerView。簡而言之,就是如果RecyclerView發生了變化,Toolbar就要相應發生變化。發生變化是具體發生什麼變化呢?這裏就要引入Behavior,Child發生變化的具體執行的代碼都是放在Behavior這個類裏面,一般用系統定義好的Behavor就可以(也可以自定義),這裏我們在RecyclerView裏面添加

        app:layout_behavior="@string/appbar_scrolling_view_behavior"

當CoordinatorLayout發現RecyclerView中定義了這個屬性,它會搜索自己所包含的其他view,看看是否有view與這個behavior相關聯。AppBarLayout.ScrollingViewBehavior描述了RecyclerView與AppBarLayout之間的依賴關係。RecyclerView的任意滾動事件都將觸發AppBarLayout或者AppBarLayout裏面view的改變。AppBarLayout裏面定義的view只要設置了app:layout_scrollFlags屬性,就可以在RecyclerView滾動事件發生的時候被觸發
app:layout_scrollFlags屬性裏面必須至少啓用scroll這個flag,這樣這個view纔會滾動出屏幕,否則它將一直固定在頂部。可以使用的其他flag有:

  • snap:當滑動停止時但未達到展開或者收縮的狀態,這個屬性會判斷距離誰最近,自動展開或者收縮(加上這個屬性效果比較順暢)

  • enterAlways: 一旦向上滾動這個view就可見

  • enterAlwaysCollapsed: 顧名思義,這個flag定義的是何時進入(已經消失之後何時再次顯示)。假設你定義了一個最小高度(minHeight)同時enterAlways也定義了,那麼view將在到達這個最小高度的時候開始顯示,並且從這個時候開始慢慢展開,當滾動到頂部的時候展開完。

  • exitUntilCollapsed: 同樣顧名思義,這個flag時定義何時退出,當你定義了一個minHeight,這個view將在滾動到達這個最小高度的時候消失。

更多方法請看官方文檔

自定義Behavior

爲了更好的理解,我將系統自帶的Behavior通過自定義來實現,同時再給FloatActionBuuton添加一個自定義的Behavior(沒有添加顯示和隱藏的動畫效果,看起來不是很美觀,但是重點不在這,對吧!嘿嘿),先看效果圖

這裏寫圖片描述

1.首先,我們定義一個類,繼承CoordinatorLayout.Behavior,其中,泛型參數T是我們要執行動作的View類,也就是Child

  • AppbarLayout的Behavior

    public class AppBehavior extends CoordinatorLayout.Behavior<AppBarLayout> {

    private int directionChange;

    public AppBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //判斷滑動的方向 返回垂直滑動
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
    }

    //根據滑動的距離顯示和隱藏 child
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
        if (dy > 0 && directionChange < 0 || dy < 0 && directionChange > 0) {
            directionChange = 0;
        }
        directionChange += dy;
        if (directionChange > child.getHeight() && child.getVisibility() == View.VISIBLE) {
            child.setVisibility(View.GONE);
        } else if (directionChange < 0 && child.getVisibility() == View.GONE) {
            child.setVisibility(View.VISIBLE);
        }
    }
}
  • Fab的Behavior和AppbarLayout的Behavior一樣,因爲泛型中的類型不同,所以還得再寫一遍

public class FabBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {

    private int directionChange;

    public FabBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //判斷滑動的方向 返回垂直滑動
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View directTargetChild, View target, int nestedScrollAxes) {
        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
    }

    //根據滑動的距離顯示和隱藏 child
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child, View target, int dx, int dy, int[] consumed) {
        if (dy > 0 && directionChange < 0 || dy < 0 && directionChange > 0) {
            directionChange = 0;
        }
        directionChange += dy;
        if (directionChange > child.getHeight() && child.getVisibility() == View.VISIBLE) {
            child.setVisibility(View.GONE);
        } else if (directionChange < 0 && child.getVisibility() == View.GONE) {
            child.setVisibility(View.VISIBLE);
        }
    }
}
  • 注意: public FabBehavior(Context context, AttributeSet attrs) {super(context, attrs);} 這個構造方法必須重寫,因爲CoordinatorLayout源碼中parseBehavior()函數中直接反射調用這個構造函數

2.在XML中給dependency添加對應的Behavior


   <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_behavior="com.coder.guoy.recyclerview.ui.coordinator.AppBehavior"><!--自定義的Behavior-->

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/colorTheme"
                android:contentInsetStart="0dp">

                <ImageView
                    android:id="@+id/imageview_back"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingBottom="20dp"
                    android:paddingLeft="5dp"
                    android:paddingRight="20dp"
                    android:paddingTop="20dp"
                    android:src="@drawable/back"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="CoordinatorLayout"
                    android:textColor="@android:color/white"/>

            </android.support.v7.widget.Toolbar>
        </android.support.design.widget.AppBarLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|right"
            android:layout_marginBottom="40dp"
            android:layout_marginRight="40dp"
            android:backgroundTint="@color/red"
            android:src="@drawable/back"
            app:borderWidth="0dp"
            app:elevation="10dp"
            app:fabSize="auto"
            app:layout_behavior="com.coder.guoy.recyclerview.ui.coordinator.FabBehavior"<!--自定義的Behavior-->
            app:pressedTranslationZ="20dp"
            app:rippleColor="@color/colorWrite"
            />

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

OK,這就完成了自定義Behavior對AppbarLayout和Fab進行控制,不需要那些繁瑣的監聽和Touch事件,這裏主要講怎樣自定義Behavior,並沒有對UI效果進行友善的處理,如果對你有幫助,Do it by yourself!

  • 注意:自定義的Behavior添加需要填寫絕對路徑(包名+類名)

Behavior中更多方法請看官方文檔

總結

我們要明確三個概念及他們之間的關係:

  • Behavior(行爲),child(子View:)和dependency(從屬者:根據子view的改變執行相應的行爲)

  • 從屬者添加定義好的行爲,當子view發生變化時,從屬者按照定義好的行爲去發生變化,

完整代碼點我下載

Thank you

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