『Material Design 入門學習筆記』CollapsingToolbarLayout 與 AppBarLayout(附 demo)

這篇文章中,介紹到的其它組件有TextInputLayout,FloatingActionButton,Snackbar,CoordinatorLayout。
該專題的其它文章:
『Material Design入門學習筆記』前言
『Material Design入門學習筆記』動畫(含demo)
『Material Design 入門學習筆記』主題與 AppCompatActivity(附 demo)
『Material Design入門學習筆記』RecyclerView與CardView(附demo)
demo下載javascript

組件介紹

CoordinatorLayout

這一篇講的組件有些多,因此要從頭提及,頭是哪呢?就是佈局文件,佈局文件的頭是哪呢?就是CoordinatorLayout。
CoordinatorLayout被譽爲超級FrameLayout。
主要是實現兩個功能:java

  • 做爲頂層佈局
  • 調度協調子佈局
    好比說,接下來會講到的Snackbar,就只有依靠CoordinatorLayout才能實現一些特殊操做,這個後面會講到。
    CoordinatorLayout功能強大,主要是依靠一個Behavior對象。CoordinatorLayout本身並不控制View,全部的控制權都在Behavior。
    這個Behavior能夠經過自定義的方式來實現本身的邏輯。寫到這裏,我忽然發現後面無法介紹了,由於介紹Behavior的功能須要依賴其它組件,那就放在後面再介紹Behavior吧。
    這裏強調一下,接下來介紹的全部組件,都會用到這個庫:
    compile 'com.android.support:design:22.2.1'複製代碼

    AppBarLayout

    AppBarLayout繼承自LinearLayout,佈局方向爲垂直方向。可是它內部封裝了一些手勢變換的動畫。
    首先它須要依賴CoordinatorLayout做爲父容器,同時也要求一個具備能夠獨立滾動的子View。
    他的子View會有一個設置參數 app:layout_scrollFlags有一下幾種設置:
  • scroll:設爲scroll的View會跟隨滾動事件一塊兒發生移動, 全部想滾動出屏幕的view都須要設置這個flag,沒有設置這個flag的view將被固定在屏幕頂部。
  • enterAlways:設爲enterAlways的View,當ScrollView往下滾動時,該View會直接往下滾動,而不用考慮ScrollView是否在滾動,這個flag讓任意向下的滾動都會致使該view變爲可見,如啓用快速「返回模式」。
  • exitUntilCollapsed:值設爲exitUntilCollapsed的View,當這個View要往上逐漸「消逝」時,會一直往上滑動,直到剩下的的高度達到它的最小高度後,再響應ScrollView的內部滑動事件。簡而言之,滾動退出屏幕,最後摺疊在頂端。
  • enterAlwaysCollapsed:是enterAlways的附加選項,通常跟enterAlways一塊兒使用,它是指,View在往下「出現」的時候,首先是enterAlways效果,當View的高度達到最小高度時(注意你的view須要設置minHeight屬性),View就暫時不去往下滾動,直到ScrollView滑動到頂部再也不滑動時,View再繼續往下滑動,直到滑到View的頂部結束。
    須要注意的是,後面兩種模式基本只有在CollapsingToolbarLayout纔有用。

    CollapsingToolbarLayout

    CollapsingToolbarLayout繼承自FrameLayout,做用是爲Toolbar提供了摺疊功能。
    下面介紹一些參數:
    app:contentScrim這個參數可讓CollapsingToolbarLayout在收縮的時候,背景圖片消失的時候,指定一個顏色。
    app:collapsedTitleGravity 指定摺疊狀態的標題如何放置,可選值:top、bottom等
    app:collapsedTitleTextAppearance指定摺疊狀態標題文字的樣貌
    app:expandedTitleTextAppearance指定展開狀態標題文字的樣貌
    app:expandedTitleGravity 展開狀態的標題如何放置
    app:titleEnabled指定是否顯示標題文本
    app:toolbarId指定與之關聯的ToolBar,若是未指定則默認使用第一個被發現的ToolBar子View
    app:expandedTitleMarginStart指定展開狀態標題距離開始位置的高度
    app:expandedTitleMarginBottom指定展開狀態標題距離底部的距離
    app:expandedTitleMarginEnd指定展開狀態標題距離結束位置的高度
    app:layout_collapseParallaxMultiplier="0.7"設置視差的係數,介於0.0-1.0之間。
    app:layout_collapseMode「pin」:固定模式,在摺疊的時候最後固定在頂端;「parallax」:視差模式,在摺疊的時候會有個視差摺疊的效果。
    app:layout_anchor``app:layout_anchorGravity兩個屬性連同一塊兒,與某一個AppBarLayout控件相關聯,肯定位置。

    TextInputLayout

    TextInputLayout控件和LinearLayout徹底同樣,它只是一個容器。跟ScrollView同樣,TextInputLayout只接受一個子元素。子元素須要是一個EditText元素。
    EditText中有一個參數hint,這個你們都不陌生,可是若是EditText放在TextInputLayout中,則會讓hint變成一個在EditText上方的浮動標籤,同時還包括一個material動畫。

    FloatingActionButton

    FloatingActionButton是一個圓形的按鈕,跟Button同樣會有點擊事件。不一樣的是,能夠設置陰影,能夠設置反饋動畫。並且若是你設置的背景圖片是一個方形的,會在圓形按鈕中間顯示。

    佈局文件

    上面介紹了一些基本屬性,如今看一下總體的佈局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                 xmlns:app="http://schemas.android.com/apk/res-auto"
                                                 android:id="@+id/main_content"
                                                 android:layout_width="match_parent"
                                                 android:layout_height="match_parent"
                                                 android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="256dp"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:fitsSystemWindows="true">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleMarginEnd="64dp">

            <ImageView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                android:src="@drawable/logo"
                app:layout_collapseMode="parallax"
                />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_collapseMode="pin" />

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

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



    <android.support.design.widget.TextInputLayout
        android:id="@+id/inputwrapper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <EditText
            android:id="@+id/input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="輸入內容"/>

    </android.support.design.widget.TextInputLayout>
    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|right|end"
        android:src="@mipmap/ic_launcher"
        android:id="@+id/btn_ok"
        />

</android.support.design.widget.CoordinatorLayout>複製代碼

在該佈局文件中使用了Toolbar,關於它的相關屬性,能夠參考我以前的文章,這裏再也不重複介紹。
TextInputLayout有人會問爲何TextInputLayout使用app:layout_behavior="@string/appbar_scrolling_view_behavior",其實爲了適配好位置,最好在外面加一層NestedScrollView,由於涉及到滑動嘛,可是這裏暫時不用,由於那是下一篇文章的內容。android

代碼

下面貼出相關的代碼:git

public class CollapsingActivity extends AppCompatActivity {
    private FloatingActionButton okBtn;
    private EditText editText;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_collapsing);
        initToolBar();
        TextInputLayout inputWrapper = (TextInputLayout) findViewById(R.id.inputwrapper);
        editText = (EditText)findViewById(R.id.input);
        okBtn = (FloatingActionButton)findViewById(R.id.btn_ok);
        okBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                hideKeyboard();
                Snackbar mySnackbar = Snackbar.make(findViewById(R.id.main_content),editText.getText().toString(),Snackbar.LENGTH_SHORT);
                mySnackbar.setAction(editText.getText().toString(), new OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        Toast.makeText(CollapsingActivity.this,"click Snackbar",Toast.LENGTH_LONG).show();
                    }
                });
                mySnackbar.show();

            }
        });
        okBtn.setCompatElevation(0);
        inputWrapper.setHintAnimationEnabled(true);
        inputWrapper.setHint("請輸入內容");
    }
    private void hideKeyboard() {
        View view = getCurrentFocus();
        if (view != null) {
            ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).
                hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }
    private void initToolBar(){
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        setTitle("CollapsingActivity");//設置標題
        toolbar.setNavigationIcon(R.mipmap.ic_launcher_round);//設置返回鍵,我這裏沒有,就有icon代替吧
        toolbar.setNavigationOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });//返回監聽
        toolbar.setSubtitle("by deep");//設置副標題
    }
}複製代碼

簡單說一下代碼的邏輯,在界面上有個輸入框,輸入內容,點擊FloatingActionButton,會將內容作一個Snackbar的展現,這是在底部會有一個Snackbar,Snackbar能夠經過setAction方法設置點擊事件,它的第一個參數是按鈕顯示的文字,第二個參數是點擊事件,我這裏是點擊Snackbar會再彈出一個Toast。
關於Snackbar的初始化,可使用make方法,這裏須要注意它的參數:github

  • 第一個參數是一個view,我試過,能夠設置界面任何一個View,可是最好設置爲父容器CoordinatorLayout,這樣的話,會有一個滑動消除的手勢。
  • 第二個參數是顯示的內容,第三個參數是顯示時長。

    自定義behavior

    在上文中提到過CoordinatorLayout功能如此強大,全依賴於Behavior對象。
    咱們先看一下源碼,Behavior是一個抽象類,public static abstract class Behavior<V extends View>,咱們能夠根據View隨意去實現。
    源碼中的實現這個抽象類的有如下幾個:
  1. AppBarLayout.Behavior;
  2. AppBarLayout.ScrollingViewBehavior;
  3. FloatingActionButton.Behavior;
  4. Snackbar.Behavior;
  5. BottomSheetBehaviro;
  6. SwipeDismissBehavior;
  7. HeaderBehavior;
  8. ViewOffsetBehavior;
  9. HeaderScrollingViewBehavior;
    其中也有抽象類。
    上面咱們用到的就有ScrollingViewBehavior和FloatingActionButton.Behavior,因爲FloatingActionButton.Behavior默認就是設置好的,因此咱們沒有在佈局文件中寫。
    那麼咱們如今能夠從新寫一個FloatingActionButton的Behavior。
    在寫以前最好去讀一下Behavior這個抽象類,其中不少概念和關聯須要弄明白。
    其中重要的兩個概念
  • child 它是一個View, 是該Behavior的關聯對象,也即Behavior所要操做的對象
  • dependency ,也是個View,是 child的依賴對象,同時也是Behavior對child進行操做的根據
    例如咱們上面那個佈局文件中child就是FloatingActionButton,dependency就是AppBarLayout。
    還有一些方法:
    layoutDependsOn用來肯定依賴關係,原文是:

    Determine whether the supplied child view has another specific sibling view as a layout dependency.
    意思是,這個view有沒有兄弟view。app

onDependentViewChangedide

Respond to a change in a child's dependent view
當咱們的 dependency 發生改變的時候,這個方法會調用,而咱們在 onDependentViewChanged 方法里根據需求作相應的界面處理便可。
咱們簡單寫一個FloatingActionButton跟隨AppBarLayout移動的例子:
```
public class CustomBehavior extends CoordinatorLayout.Behavior { 佈局

public CustomBehavior() {
}

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

@Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
   return dependency instanceof AppBarLayout;
}

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
    float translationY = Math.abs(dependency.getTop());
    Log.e("xxxxxx ","translationY="+translationY);
    child.setY(800-translationY);
    return true;
}複製代碼

}post

而後設置到佈局文件的對應位置:複製代碼


```
自定義Behavior的方式就介紹到這。
學習

總結

原本想在文章中插圖,可是因爲動圖過大,上傳老是失敗,因此,仍是請感興趣的朋友運行demo看一下效果便可。後面的文章仍是對本文的延伸,增添了一些新的組件,敬請關注。
有問題能夠給我留言,或者關注個人公衆號留言。

相關文章
相關標籤/搜索