CoordinatorLayout
是一個超級功能FrameLayout
。官方說明的功能是:android
藉助其的幫助,能夠比較方便的實現:markdown
看一下效果:左邊是標題欄吸頂效果,右邊是可伸縮的標題欄的效果。app
CoordinatorLayout
做爲一個協調器,協調子view之間的交互。經過給子view設置layout_behavior
,來決定當其餘的view發生交互的時候,視圖上如何進行響應。ide
通常來講,除了一個可滾動的view以外,還須要有AppBarLayout
和CollapsingToolbarLayout
兩個容器,來配合實現各類炫酷的效果:佈局
AppBarLayout
:默認設置了behavior,必須做爲Coordinatorlayout
的直接子view,並將圖片和標題設置在其中,其的子view可設置layout_scrollFlags
屬性,會依據這個屬性的取值,在AppBar.Behavior
執行不一樣的響應效果。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>
複製代碼
Coordinatorlayout
的直接子view具備層級的結構,佈局之間會互相覆蓋,經過指定直接子view的app:layout_behavior
,來處理不一樣子view之間的關係。this
好比下面這個效果,讓文本框跟隨按鈕的移動而移動。google
針對上面的顯示方法,先繼承實現Coordinatorlayout.Behavior
,實現其中兩個方法:spa
layoutDependsOn
:判斷給定的view和同級view是不是依賴關係。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
}
複製代碼
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>
複製代碼
AppBarlayout
的子view能夠設置的屬性,會根據取值的不一樣,在behavior
中執行不一樣的操做。
定義在AppBarLayout.LayoutPrams
中,具備六個狀態,而且各個狀態可經過取或操做疊加。
設置的方法有兩種:
<ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="wrap_content" android:scaleType="fitCenter" app:layout_scrollFlags="scroll|enterAlwaysCollapsed" />
複製代碼
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
使用。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
。
titleEnabled
:是否顯示標題,默認true。true的時候在Toolbar中設置的屬性會不起做用。title
:標題文字。expandedTitleGravity
:未摺疊的時候標題的位置,默認left|bottom
。collapsedTitleGravity
:摺疊後標題位置,默認left|center_vertical
。contentScrim
:收縮後背景的顏色,即會在ToolBar
和被摺疊的view之間再設置一層擋板。layout_collapseMode
是須要設置給子view的屬性經常使用的有兩個:
pin
:在滾動過程當中一直停留在頂部,通常設置給Toolbar
。parallax
:該視圖與頁面同時滾動,滾動的速率受到layout_collapseParallaxMultiplier
的影響,與其餘滾動反映出不同的視覺效果,逐漸隱藏。