CoordinatorLayout實現炫酷滾動嵌套

1. 介紹

CoordinatorLayout是一個超級功能FrameLayout。官方說明的功能是:android

  1. 做爲頂層的裝飾佈局。
  2. 做爲多個子視圖進行特定交互的容器。

藉助其的幫助,能夠比較方便的實現:markdown

  1. 吸頂效果。
  2. 伸縮標題欄效果。

看一下效果:左邊是標題欄吸頂效果,右邊是可伸縮的標題欄的效果。app

2. 使用

CoordinatorLayout做爲一個協調器,協調子view之間的交互。經過給子view設置layout_behavior,來決定當其餘的view發生交互的時候,視圖上如何進行響應。ide

通常來講,除了一個可滾動的view以外,還須要有AppBarLayoutCollapsingToolbarLayout兩個容器,來配合實現各類炫酷的效果:佈局

  1. AppBarLayout:默認設置了behavior,必須做爲Coordinatorlayout的直接子view,並將圖片和標題設置在其中,其的子view可設置layout_scrollFlags屬性,會依據這個屬性的取值,在AppBar.Behavior執行不一樣的響應效果。
  2. CollapsingToolbarLayout:實現能夠摺疊的標題,必須做爲AppbarLayout的子view才能實現大多數效果,子view要配合Toolbar

先看一個簡單的實現,圖中有一個圖片,一個標題欄,一個列表。跟上面第一張圖比較相似:ui

<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=".coordinator.CoordinatorActivity">

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

        <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" android:scaleType="fitXY" app:layout_scrollFlags="scroll" />

        <androidx.appcompat.widget.Toolbar android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:title="我是標題" />
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycleView" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
複製代碼

2.1. layout_behavior屬性

Coordinatorlayout的直接子view具備層級的結構,佈局之間會互相覆蓋,經過指定直接子view的app:layout_behavior,來處理不一樣子view之間的關係。this

好比下面這個效果,讓文本框跟隨按鈕的移動而移動。google

2.1.1. 自定義behavior

針對上面的顯示方法,先繼承實現Coordinatorlayout.Behavior,實現其中兩個方法:spa

  1. layoutDependsOn:判斷給定的view和同級view是不是依賴關係。
  2. onDependentViewChanged:根據依賴的視圖變化做出變化。
package com.example.mytest.coordinator.behavior

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.Button
import android.widget.TextView
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.example.mytest.Utils.px

class MyBehavior(context: Context, attrs: AttributeSet) :
    CoordinatorLayout.Behavior<TextView>(context, attrs) {
    override fun layoutDependsOn( parent: CoordinatorLayout, child: TextView, dependency: View ): Boolean {
        return dependency is Button
    }

    override fun onDependentViewChanged( parent: CoordinatorLayout, child: TextView, dependency: View ): Boolean {
        child.x = dependency.x
        child.y = dependency.y + 50.px
        return true
    }
}

複製代碼

xml佈局:code

<?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=".coordinator.CoordinatorActivity">

    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" app:layout_behavior=".coordinator.behavior.MyBehavior" />

    <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="Button" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
複製代碼

最後,設置一下button的移動:

btn.setOnTouchListener { v, event ->
    if(event.action==MotionEvent.ACTION_MOVE){
        v.x=event.rawX-v.width/2
        v.y=event.rawY-v.height/2
    }
    true
}
複製代碼

2.1.2. 自帶的behavior

CoordinatorLayout通常都會搭配AppBarlayout一塊兒使用,AppBarLayout經過註解@DefaultBehavior(AppBarLayout.Behavior.class)設置了默認的behavior,他會根據AppBarLayout子view的app:layout_scrollFalgs屬性,做出不一樣的響應行爲。

AppBarLayout配合,須要再有一個可滾動的視圖,並設置其behavior爲AppBarLayout.ScrollingViewBehavior,以下代碼實現的就是第一個gif的效果:

<?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=".coordinator.CoordinatorActivity">

    <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content">
        <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/image" android:scaleType="fitXY" app:layout_scrollFlags="scroll"/>
        <androidx.appcompat.widget.Toolbar android:layout_width="match_parent" android:layout_height="wrap_content" app:title="我是標題"/>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycleView" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

複製代碼

2.2. AppBarLayout - layout_scrollFlags屬性

AppBarlayout的子view能夠設置的屬性,會根據取值的不一樣,在behavior中執行不一樣的操做。

定義在AppBarLayout.LayoutPrams中,具備六個狀態,而且各個狀態可經過取或操做疊加。

設置的方法有兩種:

  1. xml中設置:
<ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="wrap_content" android:scaleType="fitCenter" app:layout_scrollFlags="scroll|enterAlwaysCollapsed" />

複製代碼
  1. 代碼中設置:
image.updateLayoutParams <AppBarLayout.LayoutParams>{
            scrollFlags=AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
        }
複製代碼

屬性對應的效果:

  • scroll:該視圖會響應滾動事件,其餘屬性都是以這個爲基礎。
  • enterAlways:當隱藏以後,只有滑到頂部纔會呼出。
  • enterAlwaysCollapsed:當已經隱藏的時候,從任意位置下滑均可呼出。以下,左邊是enterAlways效果,右邊是enterAlwaysCollapsed
  • snap:當滾動結束後,該視圖有一部分顯示,會回彈到最近的邊緣。
  • snapMargins:與snap配合使用,若是這個隱藏的視圖有margin,回回彈到這個margin的邊緣。以下,左邊的是隻有snap屬性,右邊是snap|snapMargins,很明顯看出一個回彈到view邊界,一個回彈到margin邊界。
  • exitUntilCollapsed:該視圖回隨着滾動而摺疊,須要配合CollapsingToolbarLayout使用。

2.3. CollapsingToolbarLayout

CollapsingToolbarLayout通常用於實現如圖所示的可摺疊標題欄。

CollapsingToolbarLayout必須做爲AppBarlayout的子view使用才能實現相關的效果,在onAttachedToWindow()的時候,會判斷直接父容器是否是AppBarLayout,若是是的話會傳入AppBarLayout.OnOffsetChangedListener監聽,綁定父佈局的滾動,進行本身的處理。若是父容器不是AppBarLayout,大部分的功能都是不起做用的。

protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    ViewParent parent = this.getParent();
    if (parent instanceof AppBarLayout) {
        ViewCompat.setFitsSystemWindows(this, ViewCompat.getFitsSystemWindows((View)parent));
        if (this.onOffsetChangedListener == null) {
            this.onOffsetChangedListener = new CollapsingToolbarLayout.OffsetUpdateListener();
        }

        ((AppBarLayout)parent).addOnOffsetChangedListener(this.onOffsetChangedListener);
        ViewCompat.requestApplyInsets(this);
    }

}
複製代碼

CollapsingToolbarLayout的子view要有一個Toobar,而且必須設置成固定高度,摺疊後的高度就是Toolbar的高度,而且標題的文字是設置給CollapsingToolbarLayout而不是Toolbar

2.3.1. 常見屬性

  • titleEnabled:是否顯示標題,默認true。true的時候在Toolbar中設置的屬性會不起做用。
  • title:標題文字。
  • expandedTitleGravity:未摺疊的時候標題的位置,默認left|bottom
  • collapsedTitleGravity:摺疊後標題位置,默認left|center_vertical
  • contentScrim:收縮後背景的顏色,即會在ToolBar和被摺疊的view之間再設置一層擋板。

layout_collapseMode是須要設置給子view的屬性經常使用的有兩個:

  • pin:在滾動過程當中一直停留在頂部,通常設置給Toolbar
  • parallax:該視圖與頁面同時滾動,滾動的速率受到layout_collapseParallaxMultiplier的影響,與其餘滾動反映出不同的視覺效果,逐漸隱藏。
相關文章
相關標籤/搜索