系列文章:
CoordinatorLayout系列(一):Behavior
CoordinatorLayout系列(二)AppBarLayout
CoordinatorLayout系列(三)AppBarLayout之layout_scrollFlags
CoordinatorLayout系列(四)CollapsingToolbarLayout
CoordinatorLayout系列(五)例子
這一篇講兩個例子,實現如下效果;
demo地址:https://github.com/whoami-I/CoordinatorLayoutExample
第一個是ToolBar能跟隨手指的上下滑動而產生漸變的效果,而不是默認的動畫,默認效果是達到某個閾值之後,就執行一個動畫把ToolBar變成綠色。
實現起來也很簡單,就是運用AppBarLayout的OnOffsetChangedListener
監聽,上代碼:
<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:collapsedTitleTextAppearance="@style/ToolbarTitleStyle"
app:contentScrim="@null"
app:expandedTitleTextAppearance="@style/BigToolbarTitleStyle"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:scrimAnimationDuration="50"
app:scrimVisibleHeightTrigger="0dp"
app:statusBarScrim="@null"
app:title="櫻花">
<ImageView
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/pic2"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
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>
佈局一般,就是把ToolBar放進CollapsingToolBarLayout
AppBarLayout.OnOffsetChangedListener listener = new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
// get total height and calc ratio
int totalHeight = mCollapsingToolbarLayout.getHeight() - mToolBar.getHeight() - ((FrameLayout.LayoutParams) mToolBar.getLayoutParams()).topMargin;
float ratio = getRatio(-verticalOffset, totalHeight);
changeToolBar(ratio); //改變toolbar透明度
changeStatusBar(ratio); //改變狀態欄顏色
}
};
// 初始化時,將toolbar設置成透明
changeToolBar(0);
private void changeStatusBar(float ratio) {
int transparent = (int) (255 * ratio);
int color = 0x008577 | (transparent << 24);
getWindow().setStatusBarColor(color);
}
private void changeToolBar(float ratio) {
mToolBar.setAlpha(ratio);
}
private float getRatio(int cur, int total) {
float ratio = 0.0f;
//這裏之所以這樣轉換,是設置toolbar開始變透明時的閾值,這個閾值爲滑動到toolbar下面100像素處,纔開始變化
int offset = 100;
if (cur >= total - offset) {
cur = cur - (total - offset);
total = offset;
ratio = cur * 1.0f / total;
ratio = ratio > 1.0f ? 1.0f : ratio;
}
return ratio;
}
添加AppBarLayout滑動監聽,然後根據滑動的距離來設置透明度信息,要注意,因爲這是我們自定義的效果,因此要先disable系統默認的效果,可以把CollapsingToolBarLayout的scrim都設置成null
app:contentScrim="@null"
app:statusBarScrim="@null"
或者是閾值改爲0
app:scrimVisibleHeightTrigger="0dp"
第二個例子也是可以用上面同樣的方式實現的,但我們換一種思路,使用自定義Behavior的方法,看看能不能行得通。
首先看佈局,因爲要使用Behavior,那麼CircleImageView肯定是作爲CoordinatorLayout的直接子view存在的
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
<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:layout_scrollFlags="scroll|exitUntilCollapsed"
app:scrimAnimationDuration="50"
app:scrimVisibleHeightTrigger="0dp">
......
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/img_head"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/head"
android:layout_gravity="center_horizontal"
app:layout_behavior=".collapsingtoolbarlayoutexample2.HeadScaleBehavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
上面的recyclerview和Toolbar都被我省略掉了
直接上Behavior吧:
public class HeadScaleBehavior extends CoordinatorLayout.Behavior<ImageView> {
private static String TAG = "HeadScaleBehavior";
public HeadScaleBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull ImageView child, @NonNull View dependency) {
//set position
int centerY = (int) ((dependency.getBottom() - dependency.getTop() + dependency.getY()) / 2);
child.setY(centerY - child.getHeight() / 2);
//set scale and alpha
float ratio = (-dependency.getY()) / (((AppBarLayout)dependency).getTotalScrollRange());
child.setScaleX(1.0f - ratio);
child.setScaleY(1.0f - ratio);
return true;
}
@Override
public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull ImageView child, @NonNull View dependency) {
return dependency instanceof AppBarLayout;
}
}
首先確定位置,因爲我們的效果是CircleImageView跟隨AppBarLayout上下移動的,但是現在的CircleImageView是位於CoordinatorLayout裏面的,因此需要知道AppBarLayout的移動距離和位置,移動距離就使用getY()方法獲取,然後計算比例的時候,需要知道AppBarLayout總共能夠滑動多少距離,使用AppBarLayout.getTotalScrollRange()
方法即可。