Material Design吸顶效果实现
目次
前言 #
Material Design是Google在2014年的I/O大会上发布的一种设计规范,包括布局、颜色、形状、声音、动效等。面向的是Android、iOS、Web和Flutter。对自己的Android,Google还推出了一系列组件、主题帮助开发者快速、方便的实现Material Design的效果。下面是几个能用在大部分实际项目中的控件:
AppBarLayout #
最近我们的项目首页UI改版,目前的布局大致如下图。打开首页时是显示tab的,向上滑动RecyclerView时超过了一定距离(比如TabLayout高度的50%)就隐藏TabLayout,下滑时超过了这距离时再显示TabLayout。

搜索时,发现有人用CoordinatorLayout+AppBarLayout实现的把ToolBar隐藏的效果。于是把我们项目中的TabLayout用AppBarLayout给包起来。达到了与期望的效果差不多的。
下面是简化了的布局。为了写起来方便用了RecyclerView,实际项目中用的则是Viewpager,除了页面左右滑动外其余都是相同的的。
布局代码如下:
| |
布局文件中最外层需要使用CoordinatorLayout,其他的就是TabLayout和一个RecyclerView。其中重要的是layout_scrollFlags和layout_behavior。
layout_behavior的作用是在有layout_behavior的CoordinatorLayout子View(NestedScrollView 、RecyclerView等)滚动时可以根据layout_scrollFlags改变AppBarLayout的行为。
layout_behavior是官方定义的,用appbar_scrolling_view_behavior。layout_scrollFlags可以根据我们需要的效果选择。
layout_scrollFlags #
在官方文档中,layout_scrollFlags的取值可以有以下七种:
noScroll #
不受RecyclerView或*NestedScrollView的滑动影响。*
scroll #
AppBarLayout在RecyclerView的第一个item或*NestedScrollView上方随着其滑动。类似插入到*RecyclerView第0个位置上。
exitUntilCollapsed #
需要与scroll一起使用,且可以设置minHeight。当向上滑动时顶部会有minHeight高度的TabLayout一直在顶部;向下滑动不会有变化,直到第0个位置的item完全显示。这时再向下滑动会逐渐恢复TabLayout原来的高度。
minHeight可以设置0dp,这时与只设置scroll无异。
enterAlways #
需要与scroll一起使用。在任何位置,向下滑动会隐藏TabLayout,向上滑动会显示TabLayout。且可以停留在TabLayout任意高度。
enterAlwaysCollapsed #
需要与scroll、enterAlways一起使用,且可以设置minHeight。向下滑动时与enterAlways相同。当向下滑动时会有minHeight高度的TabLayout一直在顶部,直到第0个位置的item完全显示。这时再向下滑动会逐渐恢复TabLayout原来的高度。
snap #
需要与scroll一起使用。与只是用scroll不同的只在TabLayout的显示和隐藏上,无论显示还隐藏只有TabLayout高度的一半时,才会变化,否则会回到当前的状态。
snapMargins #
需要与scroll、snap一起使用。当使用snap时,在TabLayout中设置marginBottom,设置的marginBottom不会随着TabLayout一起,会有marginBottom高度的一块留在顶部,需要再次滑动才能收起来。这就是snapMargins的使用场景,设置了marginBottom会随着TabLayout一起收起。
上面几种的效果其实都不是我们想要的。enterAlways没有吸顶的效果,意味着TabLayout可以显示一部分,这时用户点击Tab到其他内容页时,TabLayout的显示就会异常。而使用snap时,当TabLayout已经隐藏了,如果用户滑动到一半了就需要先回到第0个item的位置,再滑动才能显示TabLayout,体验很差。
既然有snap有吸顶效果,enterAlways又可以在任何位置位置滑出/隐藏TabLayout。有没有可能实现结合的效果呢?把两个flag都写在TabLayout上,确实实现了。但是没有文档说可以这么用,很迷惑。去看了下AppBarLayout的源码,CoordinatorLayout和AppBarLayout联动原理不再赘述。
snap的效果与enterAlways实际上是分开的。设置了SCROLL_FLAG_ENTER_ALWAYS后,从任意位置都能滑出TabLayout。又因为有snap的效果,手指松开结束滑动之后又会有吸顶的效果。