<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">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="200dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/timg" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@mipmap/back_icon"
app:title="歌曲"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="法定辅导辅导辅导辅导法定辅导辅"
android:textSize="40sp" />
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<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">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
app:layout_behavior=".AppbarZoomBehavior"
android:layout_height="200dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="100dp"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"
android:src="@mipmap/timg" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@mipmap/back_icon"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:title="歌曲" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="法定辅导辅导辅导辅导法定"
android:textSize="40sp" />
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
一下是关键代码,重写AppBarLayout.Behavior,在AppBarLayout中指定layout_behavior。
public class AppbarZoomBehavior extends AppBarLayout.Behavior {
private ImageView mImageView;
private int mAppbarHeight;
private int mImageViewHeight;
private static final float MAX_ZOOM_HEIGHT = 500;
private float mTotalDy;
private float mScaleValue;
private int mLastBottom;
private boolean isAnimate;
public AppbarZoomBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout abl, int layoutDirection) {
boolean handled = super.onLayoutChild(parent, abl, layoutDirection);
init(abl);
return handled;
}
private void init(AppBarLayout abl) {
abl.setClipChildren(false);
mAppbarHeight = abl.getHeight();
mImageView = (ImageView) abl.findViewById(R.id.imageview);
if (mImageView != null) {
mImageViewHeight = mImageView.getHeight();
}
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
isAnimate = true;
return true;
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed, int type) {
if (mImageView != null && child.getBottom() >= mAppbarHeight && dy < 0 && type == ViewCompat.TYPE_TOUCH) {
zoomHeaderImageView(child, dy);
} else {
if (mImageView != null && child.getBottom() > mAppbarHeight && dy > 0 && type == ViewCompat.TYPE_TOUCH) {
consumed[1] = dy;
zoomHeaderImageView(child, dy);
} else {
if (valueAnimator == null || !valueAnimator.isRunning()) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
}
}
}
}
private void zoomHeaderImageView(AppBarLayout abl, int dy) {
mTotalDy += -dy;
mTotalDy = Math.min(mTotalDy, MAX_ZOOM_HEIGHT);
mScaleValue = Math.max(1f, 1f + mTotalDy / MAX_ZOOM_HEIGHT);
ViewCompat.setScaleX(mImageView, mScaleValue);
ViewCompat.setScaleY(mImageView, mScaleValue);
mLastBottom = mAppbarHeight + (int) (mImageViewHeight / 2 * (mScaleValue - 1));
abl.setBottom(mLastBottom);
}
@Override
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY) {
if (velocityY > 100) {
isAnimate = false;
}
return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
}
@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl, View target, int type) {
recovery(abl);
super.onStopNestedScroll(coordinatorLayout, abl, target, type);
}
ValueAnimator valueAnimator;
private void recovery(final AppBarLayout abl) {
if (mTotalDy > 0) {
mTotalDy = 0;
if (isAnimate) {
valueAnimator = ValueAnimator.ofFloat(mScaleValue, 1f).setDuration(220);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
ViewCompat.setScaleX(mImageView, value);
ViewCompat.setScaleY(mImageView, value);
abl.setBottom((int) (mLastBottom - (mLastBottom - mAppbarHeight) * animation.getAnimatedFraction()));
}
});
valueAnimator.start();
} else {
ViewCompat.setScaleX(mImageView, 1f);
ViewCompat.setScaleY(mImageView, 1f);
abl.setBottom(mAppbarHeight);
}
}
}
}
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="200dp"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:statusBarScrim="?attr/colorPrimary">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@mipmap/timg" />
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@mipmap/back_icon"
app:title="测试" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="法定辅导辅导辅导辅导法"
android:textSize="40sp" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|end"
app:srcCompat="@android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
1,fitsSystemWindows
首先需要了解一下主题配置,我们通常在style中设置的主题有什么用呢,如下代码:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
假如我们要实现如下效果,布局中的一张图片填充大了状态栏。首先需要将statusBarColor设置成透明,然后在使用fitsSystemWindows属性。
首先需要设置在values-v21中设置主题
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<ImageView
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:background="@mipmap/timg"
android:fitsSystemWindows="true" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
图片填充到状态栏 android:fitsSystemWindows="true"起到了关键作用。也就是说这个属性为true状态栏会填充当前view内容。
如下效果,想让状态栏同步AppBarLayout的颜色。
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:fitsSystemWindows="true">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/ThemeOverlay.AppCompat.Light"
app:navigationIcon="@mipmap/back_icon"
app:title="测试" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
这里的AppBarLayout中设置了android:fitsSystemWindows=“true”,因此状态栏就一致了。
2,view设置主题
如下给Toolbar设置主题,AppCompat.Light主题是白底黑字,theme是给当前view以及子view设置主题,popupTheme是给弹出菜单设置主题。
android:theme="@style/ThemeOverlay.AppCompat.Light"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
3, CollapsingToolbarLayout中属性
在上文 “效果三” 中,contentScrim是当页面往上滑动CollapsingToolbarLayout折叠后背景颜色,如果不设置,显示图片的一部分。statusBarScrim自然就是往上滑动后显示状态栏的颜色了。
app:contentScrim="?attr/colorPrimary"
app:statusBarScrim="?attr/colorPrimary"
4,Toolbar中的属性
在上文 “效果三” 中,Toolbar中的layout_collapseMode属性。
pin : 当CollapsingToolbarLayout完全收缩后,Toolbar还可以保留在屏幕上。
parallax:在内容滚动时,CollapsingToolbarLayout中的View(比如ImageView)也可以同时滚动,
实现视差滚动效果,通常和layout_collapseParallaxMultiplier(设置视差因子)搭配使用。
app:layout_collapseMode="pin"
看个效果,就理解layout_collapseMode和layout_collapseParallaxMultiplier配合使用了。还是 “效果三” 中的代码,把AppBarLayout宽度调成300dp便于观看,然后在ImageView中添加如下代码
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"
注意看背景图片,这个效果和 “效果三” 中不同之处就是这个图片有伸缩的效果,而不是直接滑上去。
5,anchor属性
关键词:layout_anchor和layout_anchorGravity。
简单说明:child B通过layout_anchor 设置child A为anchor,再通过layout_anchorGravity来根据需要设置属性,这样B就可以A的位移相应的位移了。
这就是 “效果三” 中FloatingActionButton的效果。