系列文章:
CoordinatorLayout系列(一):Behavior
CoordinatorLayout系列(二)AppBarLayout
CoordinatorLayout系列(三)AppBarLayout之layout_scrollFlags
CoordinatorLayout系列(四)CollapsingToolbarLayout
CoordinatorLayout系列(五)例子
終於到CollapsingToolbarLayout這個強大而裝逼的佈局了,這個佈局的實現和原理都是非常的簡單,比如下面的效果:
是不是很酷?當然這還是比較簡單的,這僅僅是使用到了系統自帶的一些功能,通過自定義可以實現更復雜的效果。
demo地址:https://github.com/whoami-I/CoordinatorLayoutExample
先講實現的方式,再講實現的過程。
實現原理
通過查看CollapsingToolBarLayout的源代碼,發現其實現方式非常簡單,源代碼加在一起也就1000多行,其實簡單的原因有兩方面,一是CollapsingToolBarLayout其實是一個FrameLayout;二是因爲這種效果的核心實現其實是CoordinatorLayout和AppBarLayout,CollapsingToolBarLayout其實是基於兩者之上稍微拓展了一下而已。
在之前的文章中講過,當滑動下面的NestedScrollView時,由於NestedScroll機制最終會導致AppBarLayout的child view滑動,所以只需要建立起AppBarLayout和CollapsingToolBarLayout的關聯即可。
AppBarLayout有一個內部類OnOffsetChangedListener
這個就是用以監聽AppBarLayout滑動的距離:
public interface OnOffsetChangedListener extends BaseOnOffsetChangedListener<AppBarLayout> {
void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset);
}
verticalOffset代表滑動距離,向上滑動這個值小於0,向上滑動大於0.
CollapsingToolBarLayout就是實現這個監聽,根據滑動的距離,實現不同的動作,比如:標題的移動和放大縮小、ToolBar的透明度等等。
實現過程
上佈局
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentScrim="@color/colorPrimary"
app:title="風景"
app:scrimAnimationDuration="50"
app:collapsedTitleTextAppearance="@style/ToolbarTitleStyle"
app:expandedTitleTextAppearance="@style/BigToolbarTitleStyle"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/pic1"
app:layout_collapseMode="parallax" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
<!--把toolbar背景設置成透明-->
android:background="#00000000"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_arrow_back"
app:titleTextAppearance="@style/ToolbarTitleStyle"></androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
先理解CollapsingToolBarLayout幾個屬性的意義:
app:contentScrim :表示收縮時,CollapsingToolBarLayout的遮擋顏色
app:statusBarScrim :表示收縮時,狀態欄的遮擋顏色
app:collapsedTitleTextAppearance :收縮最終狀態時,title的樣式
app:expandedTitleTextAppearance :展開最終狀態時,title的樣式
app:scrimAnimationDuration : 遮擋顏色以動畫的形式出現,該值表示動畫時長
app:layout_collapseMode : pin表示收縮時,此view不參與滑動,默認爲parallax表示會參與滑動
在這裏要注意title要設置到CollapsingToolBarLayout上,而不是ToolBar,否則會導致title樣式不對,具體原因是CollapsingToolBarLayout自己本身就會根據移動的距離,動態畫出一個title,因此ToolBar就沒有必要設置title了,設置完這些就有效果了:
狀態欄顏色不對,這是因爲沒有實現沉浸,而且需要把狀態欄顏色改成透明,在setContentView之前:
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
getWindow().setStatusBarColor(Color.TRANSPARENT);
沉浸之後,ToolBar也會到狀態欄後面,因此需要將ToolBar下移一個狀態欄的高度:
FrameLayout.LayoutParams lps = (FrameLayout.LayoutParams) mToolBar.getLayoutParams();
lps.topMargin = DisplayUtils.getStatusBarHeight(this);
設置完之後的效果:
差不多了,就是遮擋顏色scrim出現的時機不是很好,我們需要它在接近於頂部的時候纔出現,因此還需要設置CollapsingToolBarLayout的ScrimVisibleHeightTrigger
屬性:
ViewTreeObserver vto = mAppBarLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mAppBarLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(mToolBar.getHeight()+1+DisplayUtils.getStatusBarHeight(MainActivity.this));
}
});
這樣就達到開頭的效果了。至於上面爲什麼+1,看源碼就ok了。
接下來的文章就準備實現下拉的時候,如何使得圖片能夠放大,而且再寫幾個例子實現自定義的效果。