跳至主要內容

Android 实现可折叠 toolbar

JI,XIAOYONG...大约 5 分钟

使用到的类有:

  • 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 的效果。

具体实现

源码:githubopen in new window

<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>
  1. CoordinatorLayout 在最外层,注意其直接子 view 必须就是要实现联动的 view,否则联动失效。
  2. CollapsingToolbarLayout 必须设置 layout_scrollFlags,其余属性可选。

layout_scrollFlags 说明如下:

scroll:所有想滚动出屏幕的 view 都需要设置这个 flag,没有设置这个 flag 的 view 将被固定在屏幕顶部。

enterAlways:这个 flag 让任意向下的滚动都会导致该 view 变为可见,启用快速“返回模式”。

enterAlwaysCollapsed:假设你定义了一个最小高度(minHeight)同时 enterAlways 也定义了,那么 view 将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。

exitUntilCollapsed:当你定义了一个 minHeight,此布局将在滚动到达这个最小高度的时候折叠。

snap:当一个滚动事件结束,如果视图是部分可见的,那么它将被滚动到收缩或展开。例如,如果视图只有底部 25% 显示,它将折叠。相反,如果它的底部 75% 可见,那么它将完全展开。

作者:尹 star

链接:https://www.jianshu.com/p/5287d090e777open in new window

  1. CollapsingToolbarLayout 的子 view 需要指定 layout_collapseMode,还有一点需注意:和 toolbar 联动的子 view 高度需大于 toolbar 高度,否则无效果。
  2. 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 有两个目的:

  1. 将两个或多个子 view 绑定;
  2. 将一个子 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 的总结

  1. 确定 CoordinatorLayout 中 View 与 View 之间的依赖关系,通过 layoutDependsOn() 方法,返回值为 true 则依赖,否则不依赖。
  2. 当一个被依赖项 dependency 尺寸或者位置发生变化时,依赖方会通过 Byhavior 获取到,然后在 onDependentViewChanged 中处理。如果在这个方法中 child 尺寸或者位置发生了变化,则需要 return true。
  3. 当 Behavior 中的 View 准备响应嵌套滑动时,它不需要通过 layoutDependsOn() 来进行依赖绑定。只需要在 onStartNestedScroll() 方法中通过返回值告知 ViewParent,它是否对嵌套滑动感兴趣。返回值为 true 时,后续的滑动事件才能被响应。
  4. 嵌套滑动包括滑动 (scroll) 和 快速滑动 (fling) 两种情况。开发者根据实际情况运用就好了。
  5. Behavior 通过 3 种方式绑定:1. xml 布局文件。2. 代码设置 layoutparam。3. 自定义 View 的注解。

来源:针对 CoordinatorLayout 及 Behavior 的一次细节较真 - frank 的专栏 - CSDN 博客open in new window

参考文献

文章标题:《Android 实现可折叠 toolbar》
本文作者: JI,XIAOYONG
发布时间: 2018/02/22 15:01:10 UTC+8
更新时间: 2023/12/30 16:17:02 UTC+8
written by human, not by AI
本文地址: https://jixiaoyong.github.io/blog/posts/b4832cd1.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 许可协议。转载请注明出处!
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8