A super-powered FrameLayout—協(xié)調(diào)布局CoordinatorLayout(一):深度基本了解

如果你想了解Behavior,可以移步另一篇文章
A super-powered FrameLayout—協(xié)調(diào)布局CoordinatorLayout(二):Behavior

一、CoordinatorLayout介紹

CoordinatorLayout is a super-powered FrameLayout.
CoordinatorLayout is intended for two primary use cases:
  1. As a top-level application decor or chrome layout
     (作為頂級應(yīng)用程序或者框架布局)
  2. As a container for a specific interaction with one or more child views
      (作為與一個或者多個child view 進(jìn)行特定交互的容器)

By specifying Behaviors for child views of a CoordinatorLayout you can provide many different interactions within a single parent and those views can also interact with one another. View classes can specify a default behavior when used as a child of a CoordinatorLayout using the CoordinatorLayout.DefaultBehavior annotation.
(通過為 CoordinatorLayout 的子view指定 Behaviors,您可以在單個父視圖中提供很多不同的交互,并且這些視圖也可以相互交互。當(dāng)視圖類用作 CoordinatorLayout 的子項時,可以使用CoordinatorLayout.DefaultBehavior 注釋指定默認(rèn)行為)

Behaviors may be used to implement a variety of interactions and additional layout modifications ranging from sliding drawers and panels to swipe-dismissable elements and buttons that stick to other elements as they move and animate.
 (Behaviors可以提供很多很多牛批的交互,炫酷的效果)

Children of a CoordinatorLayout may have an anchor. This view id must correspond to an arbitrary descendant of the CoordinatorLayout, but it may not be the anchored child itself or a descendant of the anchored child. This can be used to place floating views relative to other arbitrary content panes.

Children can specify CoordinatorLayout.LayoutParams.insetEdge to describe how the view insets the CoordinatorLayout. Any child views which are set to dodge the same inset edges by CoordinatorLayout.LayoutParams.dodgeInsetEdges will be moved appropriately so that the views do not overlap.

二、基本使用

1. 配合AppBarLayout使用

1.1關(guān)于layout_scrollFlags屬性的解釋

layout_scrollFlags中的屬性可以相互結(jié)合使用,用于實現(xiàn)不同的效果
注意:exitUntilCollapsedenterAlways、 enterAlwaysCollapsedsnap、snapMargins必須結(jié)合scroll使用才會生效

屬性名 xml 說明
SCROLL_FLAG_NO_SCROLL noScroll 禁用視圖上的滾動。此標(biāo)志不應(yīng)與任何其他滾動標(biāo)志結(jié)合使用
SCROLL_FLAG_SCROLL scroll 視圖將與滾動事件直接相關(guān)。需要設(shè)置此標(biāo)志才能使任何其他標(biāo)志生效。如果在此之前的任何兄弟視圖沒有此標(biāo)志,則此值無效
SCROLL_FLAG_EXIT_UNTIL_COLLAPSED exitUntilCollapsed 視圖滾動時,目標(biāo)視圖將折疊,折疊高度由視圖的最小高度決定,當(dāng)滾動視圖到頂部時展開
SCROLL_FLAG_ENTER_ALWAYS enterAlways 隨著上下滾動事件,立即折疊或展開
SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED enterAlwaysCollapsed 初始狀態(tài)下隨著向上滾動開始折疊,向下滾動時到達(dá)初始狀態(tài)后開始展開
SCROLL_FLAG_SNAP snap 在滾動結(jié)束時,如果視圖只是部分可見,那么它將被捕捉并滾動到它最近的邊緣
SCROLL_FLAG_SNAP_MARGINS snapMargins 與 'snap' 一起使用的附加標(biāo)志。如果設(shè)置,視圖將捕捉到其頂部和底部邊距,而不是視圖本身的邊緣

1.2 layout_scrollFlags的對應(yīng)效果

文字的描述始終是沒有看圖來的直接,先貼布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.AppCompatImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:minHeight="50dp"
            android:src="@mipmap/test"
            app:layout_scrollFlags="noScroll" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <androidx.appcompat.widget.AppCompatTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center_horizontal"
            android:lineSpacingExtra="20dp"
            android:text="@string/it_is_a_man"
            android:textSize="23sp" />

    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
1.2.1 layout_scrollFlagsnoScroll

圖片不會隨著的滾動做出任何變化


noScroll.gif
1.2.2 layout_scrollFlagsscroll

圖片好像是嵌套在NestedScrollView頂部一樣,隨著滾動改變了原本的位置


scroll.gif
1.2.3 layout_scrollFlagsscroll|exitUntilCollapsed
  • 向上開始滑動時,圖片開始隨著滑動向上滑動,直到達(dá)到設(shè)置ImageView的最小高度時(我這里設(shè)置的是50dp),圖片不會再隨著滑動繼續(xù)滑動
  • 向下滑動時(注意細(xì)節(jié)),圖片不會隨著滑動立馬展開,而是當(dāng)NestedScrollView滑動到頂部時,繼續(xù)向下滑動,此時圖片才會隨著滑動展開


    scroll|exitUntilCollapsed.gif
1.2.4 layout_scrollFlagsscroll| enterAlways
  • 向上開始滑動時,圖片開始隨著滑動向上滑動,直到完全離開可視區(qū)域,無視最小高度的屬性
  • 向下滑動時(注意細(xì)節(jié)),圖片會立馬開始跟隨滑動展開,直到圖片完整展開時,NestedScrollView中的內(nèi)容才會隨著繼續(xù)滑動展示


    scroll|enterAlways.gif
1.2.5 layout_scrollFlagsscroll| enterAlwaysCollapsed
  • 向上開始滑動時,圖片開始隨著滑動向上滑動,直到完全離開可視區(qū)域,無視最小高度的屬性
  • 向下滑動時(注意細(xì)節(jié)),圖片不會隨著滑動立馬展開,而是當(dāng)NestedScrollView滑動到頂部時,繼續(xù)向下滑動,此時圖片才會隨著滑動展開


    scroll|enterAlwaysCollapsed.gif
1.2.6 layout_scrollFlagsscroll|snap

當(dāng)手指一直處于屏幕上滑動,效果和scroll| enterAlwaysCollapsed完全相同,它倆的區(qū)別在于,當(dāng)在滑動的過程中圖片還可見時手指離開屏幕的效果

  • 當(dāng)圖片滑動未超過圖片高度的1/2時,回彈到全部展開狀態(tài)
  • 當(dāng)超過1/2時,自動滑動到全部收縮狀態(tài)


    scroll|snap.gif
1.2.7 layout_scrollFlagsscroll|snap| snapMargins

scroll|snap基本一樣,唯一的區(qū)別是,自動滑動到的并非是圖片的頂部或者底部,而是會加上marginTop或者marginBottom的距離。

修改xml,給ImageView增加margin屬性

    // 增加margin屬性
...
    <androidx.appcompat.widget.AppCompatImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:minHeight="50dp"
        android:src="@mipmap/test"
        android:layout_marginVertical="30dp"
        app:layout_scrollFlags="scroll|snap|snapMargins" />
...
scroll|snap|snapMargins.gif

到此AppBarLayoutlayout_scrollFlags屬性值對應(yīng)的不同的效果就介紹完了,下面再介紹一下,經(jīng)常和CoordinatorLayout&AppBarLayout一起使用的另外一個控件CollapsingToolbarLayout(折疊工具欄布局)

2. 配合CollapsingToolbarLayout使用

CollapsingToolbarLayout是一個實現(xiàn)了折疊app bar的wrapper(包裝器),它只能用作AppBarLayout的直接子View —— 來自官方類說明(靈魂翻譯)

2.1 CollapsingToolbarLayout這廝的layout_collapseMode屬性也有flag

  • none —— view將正常運行,沒有折疊行為
  • pin —— view將固定在那個位置
  • parallax —— view將以視差方式滾動

xml布局文件如下??

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <androidx.appcompat.widget.AppCompatImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:adjustViewBounds="true"
                android:src="@mipmap/test"
                app:layout_collapseMode="parallax" />

            <View
                android:layout_width="match_parent"
                android:layout_height="?android:actionBarSize"
                android:background="@mipmap/test"
                app:layout_collapseMode="pin"/>

<!--            <androidx.appcompat.widget.Toolbar-->
<!--                android:layout_width="match_parent"-->
<!--                android:layout_height="?android:actionBarSize"-->
<!--                app:layout_collapseMode="pin"-->
<!--                android:background="@mipmap/test"/>-->

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <androidx.appcompat.widget.AppCompatTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center_horizontal"
            android:lineSpacingExtra="20dp"
            android:text="@string/it_is_a_man"
            android:textSize="23sp" />

    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
2.1.1 layout_collapseModenonepin

經(jīng)不完全測試,pin值只對Toolbar控件設(shè)置起作用,其他控件設(shè)置none或者pin沒啥區(qū)別(結(jié)論草率,細(xì)糾大佬還請賜教)

ImageView + View

ImageView + ToolBar

2.1.1 layout_collapseModeparallax

以視差方式滾動,仔細(xì)看,隨著滑動,并不是單純的上下一起折疊/展開,整體圖片還伴隨的滑動,這種視差效果可以通過layout_collapseParallaxMultiplier屬性來設(shè)置,取值[0,1],默認(rèn)值為0.5

layout_collapseParallaxMultiplier =0.5

隨著CollapsingToolbarLayout簡單介紹完畢,CoordinatorLayout+ AppBarLayout + CollapsingToolbarLayout +Toolbar +NestedScrollingChild(經(jīng)常使用的NestedScrollView或RecyclerView),這一套最基礎(chǔ)的搭配使用就基本介紹完畢了。

3 應(yīng)用場景

有哪些應(yīng)用場景呢,這個只能說仁者見仁了。

  • CollapsingToolbarLayout 配合Toolbar ,在詳情頁里比較常見;
  • 還有常用到的是在頁面滑動過程中,有些控件需要懸停在頂部,比如懸停TabLayout,方便用戶切換tab


    應(yīng)用場景

4 彩蛋總是在最后

4.1 重中之重——Behavior

當(dāng)你看完前面的內(nèi)容,感覺自己又可以了的時候,我要把你拉回來,那些只是皮毛上的毛皮,只是最最基本的使用。
思考一個問題,為什么使用CoordinatorLayout做為父布局,子View之間就會產(chǎn)生相互作用,這到底是誰在搞事情,它不是CoordinatorLayout,而是Behavior,理論上CoordinatorLayout的直接子view必須設(shè)置Behavior,這樣才能實現(xiàn)子view間的相互作用;當(dāng)然了你也可以不設(shè)置,那它就是個傻傻的控件。

看xml布局的<androidx.core.widget.NestedScrollView ...有個layout_behavior屬性,設(shè)置的是@string/appbar_scrolling_view_behavior

 <string name="appbar_scrolling_view_behavior" translatable="false">com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior</string>
    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
  ...

AppBarLayout并沒有設(shè)置layout_behavior屬性,為什么可以隨著滑動做出相應(yīng)的效果

 <com.google.android.material.appbar.AppBarLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content">

...

莫要著急,點進(jìn)去,看看AppBarLayout的實現(xiàn),當(dāng)看到implements CoordinatorLayout.AttachedBehavior,一切都很明朗了

public class AppBarLayout 
          extends LinearLayout
          implements CoordinatorLayout.AttachedBehavior {

...

4.2 總結(jié):設(shè)置Behavior的幾種方式

  • AppBarLayout一樣,View直接實現(xiàn)CoordinatorLayout.AttachedBehavior
  • 通過CoordinatorLayout.LayoutParamssetBehavior(···)方法設(shè)置
  • (常用)新建子類繼承自CoordinatorLayout.Behavior,重寫其中的方法,通過layout_behavior屬性設(shè)置

通過layout_behavior屬性設(shè)置分2種方式

  • 直接設(shè)置該子類的全路徑包名,例如
<androidx.core.widget.NestedScrollView
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
...
  • 將該子類的全路徑包名寫到string.xml中,通過@string/xxxx的方式設(shè)置
<androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
...

關(guān)于重寫CoordinatorLayout.Behavior,我決定再開一篇單獨的文章。
本身這篇文章篇幅已經(jīng)很長了,再者我也累了,正兒八經(jīng)寫文章實則不易。


如果文章對你有幫助,點個贊再走唄

如果文章中存在錯誤,還望評論區(qū)指出

一起成長,共同進(jìn)步

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容