UI-折叠布局CollapsingToolbarLayout

CollapsingToolbarLayout

简介

  • 一个FrameLayout
  • 用于实现可折叠的标题栏,通常在子布局中放一个Toolbar
  • 必须作为 AppBarLayout 的子类,才能发挥出效果

xml属性

CollapsingToolbarLayout 中的部分属性

  • collapsedTitleGravity:折叠态标题位置
  • collapsedTitleTextAppearance:折叠态标题外观
  • expandedTitleGravity:扩展态标题位置
  • expandedTitleMargin*:扩展态标题的Margin。注意与expandedTitleGravity可能冲突
  • expandedTitleTextAppearance:扩展态后标题的外观
  • contentScrim:折叠态后Toolbar颜色
  • scrimAnimationDuration:收缩或展开时颜色动画持续时间。需要设置contentScrim生效
  • scrimVisibleHeightTrigger:触发高度。小于的时候,展示contentScrim,否则不展示
  • toolbarId:折叠态的时候显示的Toolbarid

CollapsingToolbarLayout 中还需要使用 AppBarLayout 中的属性

  • app:layout_scrollFlags:具体参考AppBarLayout中的Flag用法

CollapsingToolbarLayoutview中用到的属性(CollapsingToolbarLayout.LayoutParams

  • layout_collapseMode :折叠模式。三种取值

    • COLLAPSE_MODE_OFF (none) :等于没设置

    • COLLAPSE_MODE_PARALLAX (parallax) :view将以视差方式滚动

      上面大图部分的父ViewCollapsingToolbarLayout,对ImageView设置了parallax,效果就是上下各一半的减少,最后显示的位置是图片的正中央

    • COLLAPSE_MODE_PIN (pin) :view固定在适当位置,直到达到CollapsingToolbarLayout底部。就相当于View被整个推上去或者拉下来的效果

  • layout_collapseParallaxMultiplier : 视差系数。layout_collapseMode设置为parallax才生效。不设置视差系数,默认为0.5,就是收缩时上下各自收缩一半。视差系数决定下面收缩比例。

    如:对ImageView设置视差系数为0.2,可以看到收缩的时候,下面收缩的比较慢,上面收缩的比较快。实际上下面没收缩2px,上面就收缩8px,收缩速度是下面的4倍

例子

597直聘的

Img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//布局关闭时顶部距离
float LL_SEARCH_MIN_TOP_MARGIN = KStatusBarUtils.getStatusBarHeight(getContext());
float TV_LOGO_MAX_TOP_MARGIN = KDisplayUtils.dip2px(getContext(), 11.5f);
//这边是用的AppBarLayout位移监听
mBinding.appbarHomePosition
.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
if (mCurrentAppBarOffset == verticalOffset) {
return;
}
if (mBinding != null) {
//设置开关banner的滚动
setBannerTurning(verticalOffset == 0);
//布局位移过程中设置顶部标题的透明度
float dy = Math.abs(verticalOffset * 0.6f);
float logoTopMargin = (float) (TV_LOGO_MAX_TOP_MARGIN - dy * 0.5);
float logoAlpha = 255 * logoTopMargin / TV_LOGO_MAX_TOP_MARGIN;
if (logoAlpha < 0) {
logoAlpha = 0;
}
mBinding.toolbarHomePosition.getLeftIconView(0).setImageAlpha((int) logoAlpha);
//处理布局的边界问题
float searchLayoutNewTopMargin = LL_SEARCH_MAX_TOP_MARGIN - dy;
if (searchLayoutNewTopMargin < LL_SEARCH_MIN_TOP_MARGIN) {
searchLayoutNewTopMargin = LL_SEARCH_MIN_TOP_MARGIN;
}
//设置相关控件的LayoutParams 此处使用的是MarginLayoutParams,便于设置params的topMargin属性
mSearchBarParams.topMargin = (int) searchLayoutNewTopMargin;
mBinding.homeSearchBar.setLayoutParams(mSearchBarParams);
mBinding.homeSearchBar.setViewsAlpha(logoAlpha);

mCurrentAppBarOffset = verticalOffset;
}
});

布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<!--顶部标题栏,可根据监听AppBarLayout的位移来计算,最后一个child覆盖另一个child-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
app:contentInsetEnd="0dp"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin"
app:layout_scrollFlags="exitUntilCollapsed|enterAlways|enterAlwaysCollapsed">

<!--顶部标题栏(待覆盖的child)-->
<com.xm597.app.project.ui.position.view.HomePositionToolbar
android:id="@+id/toolbar_home_position"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorEE5647" />

<!--(AppBarLayout往上位移)最终覆盖的child-->
<com.xm597.app.project.ui.position.view.HomePositionToolbarV1
android:id="@+id/home_search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/viewSize8" />
</RelativeLayout>

<com.scwang.smart.refresh.layout.SmartRefreshLayout
...>

<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/cdl_home_position"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_home_position"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite">

<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/ctl_home_position"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
app:contentScrim="@color/colorWhite"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:scrimAnimationDuration="500">

<!--跟随移动,最终折叠的部分-->
<LinearLayout
...>
</LinearLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout>

<!--跟随移动,最终悬浮的部分【可选】-->

</com.google.android.material.appbar.AppBarLayout>

<!--底部普通内容-->
<androidx.recyclerview.widget.RecyclerView
... />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
</LinearLayout>