Android 实现可折叠 toolbar
使用到的类有:
- android.support.design.widget.CoordinatorLayout
- android.support.design.widget.AppBarLayout
- android.support.design.widget.CollapsingToolbarLayout
- android.support.v7.widget.Toolbar
效果预览
如图:
简要说明
CoordinatorLayout 类,协调者布局,通过 Behavior 将一个子 view(child
)的行为和另一个子 view(dependency
)的活动联结起来,从而实现子 view 之间的联动。
AppBarLayout 类,是一个实现了材料设计的默认垂直布局的 ViewGroup,当其是 CoordinatorLayout 类的直接子 view 时,另外一个 CoordinatorLayout 的子 view 指定了 behavior 为 AppBarLayout.ScrollingViewBehavior 的实例(app:layout_behavior="@string/appbar_scrolling_view_behavior"
),且该子 view 需要是 NestedScrollingChild 的实现类。
CollapsingToolbarLayout 类,提供一个可以折叠的 toolbar 布局,可以在这个布局里面,设置 toolbar 以及和 toolbar 一起联动的子 view,本案例中是一张图片。
Toolbar 类,实现 toolbar 的效果。
具体实现
源码:github
<android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
- CoordinatorLayout 在最外层,注意其直接子 view 必须就是要实现联动的 view,否则联动失效。
- CollapsingToolbarLayout 必须设置 layout_scrollFlags,其余属性可选。
layout_scrollFlags 说明如下:
scroll:所有想滚动出屏幕的 view 都需要设置这个 flag,没有设置这个 flag 的 view 将被固定在屏幕顶部。
enterAlways:这个 flag 让任意向下的滚动都会导致该 view 变为可见,启用快速“返回模式”。
enterAlwaysCollapsed:假设你定义了一个最小高度(minHeight)同时 enterAlways 也定义了,那么 view 将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。
exitUntilCollapsed:当你定义了一个 minHeight,此布局将在滚动到达这个最小高度的时候折叠。
snap:当一个滚动事件结束,如果视图是部分可见的,那么它将被滚动到收缩或展开。例如,如果视图只有底部 25% 显示,它将折叠。相反,如果它的底部 75% 可见,那么它将完全展开。
作者:尹 star
- CollapsingToolbarLayout 的子 view 需要指定 layout_collapseMode,还有一点需注意:和 toolbar 联动的子 view 高度需大于 toolbar 高度,否则无效果。
- ViewPager 就是本案例中触发子 view 联动效果的
dependency
,需要指定其 behavior:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
其实际对应于 android.support.design.widget.AppBarLayout$ScrollingViewBehavior,这个是系统实现的一个 behavior,用于和嵌套滑动事件绑定,指定该 behavior 的子 view 需要是 NestedScrollingChild 的实现类(系统提供了 4 个实现类:NavigationMenuView、NestedScrollView、RecyclerView、SwipleRefreshLayout),所以 viewPager 中页面有上述 4 个类或其子类时,才能实现绑定效果。
延伸
自定义 Behavior
自定义 Behavior 有两个目的:
- 将两个或多个子 view 绑定;
- 将一个子 view 与另一个子 view 的滑动事件绑定在一起
两者的差异在于在实现CoordinatorLayout.Behavior<T>
类时候具体重写的方法不一样。
目的 1:需要重写的方法有:
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, T child, View dependency) {
//如果 dependency 是要依赖的子 view(此处是 TempView 类)的实例,说明它就是我们所需要的 Dependency
return dependency instanceof TempView;
}
//每次 dependency 位置发生变化,都会执行 onDependentViewChanged 方法
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, T child, View dependency) {
//根据 dependency 的位置,设置 child 的位置,对 child 进行想要实现的变化
return true;//返回 true 表示改变了 child 的尺寸和位置参数,否则返回 false
}
目的 2:需要重写的方法有:
//判断是否要开始根据 dependency 子 view 的行为改变 child 的状态
@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull ImageView child,@NonNull View directTargetChild, @NonNull View target, int axes, int type) {
return child instanceof ImageView && axes == View.SCROLL_AXIS_VERTICAL;//子 view 是 ImageView,并且滑动的方向是垂直的
}
//当 dependency 子 view 滑动时,对 child 进行相应处理
@Override
public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull ImageView child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
}
自定义 Behavior 的总结
- 确定 CoordinatorLayout 中 View 与 View 之间的依赖关系,通过 layoutDependsOn() 方法,返回值为 true 则依赖,否则不依赖。
- 当一个被依赖项 dependency 尺寸或者位置发生变化时,依赖方会通过 Byhavior 获取到,然后在 onDependentViewChanged 中处理。如果在这个方法中 child 尺寸或者位置发生了变化,则需要 return true。
- 当 Behavior 中的 View 准备响应嵌套滑动时,它不需要通过 layoutDependsOn() 来进行依赖绑定。只需要在 onStartNestedScroll() 方法中通过返回值告知 ViewParent,它是否对嵌套滑动感兴趣。返回值为 true 时,后续的滑动事件才能被响应。
- 嵌套滑动包括滑动 (scroll) 和 快速滑动 (fling) 两种情况。开发者根据实际情况运用就好了。
- Behavior 通过 3 种方式绑定:1. xml 布局文件。2. 代码设置 layoutparam。3. 自定义 View 的注解。
来源:针对 CoordinatorLayout 及 Behavior 的一次细节较真 - frank 的专栏 - CSDN 博客