仿知乎底部导航栏隐藏效果
效果如下:

AppBarLayout在向上滑动的时候会隐藏,向下滑动的时候会展示,需要给AppBarLayout的子View设置app:layout_scrollFlags=”scroll|enterAlways”,核心代码如下:
1 | <com.google.android.material.appbar.AppBarLayout |
这里使用RadioGroup来实现tab的切换,可以看到,向上滑动的时候它会隐藏,向下滑动的时候会显示,其实只是给其设置了behavior。
第一种实现方式
代码如下:
1 | /** |
child是我们要改变的坐标的view,它会随着dependency坐标的改变而改变。把这个FooterBehaviorDependAppBar设置给RadioGroup的时候,这时候child就是RadioGroup,而dependency就是AppBarLayout,因为我们在layoutDependsOn方法里面,返回dependency instanceof AppBarLayout,即当dependency是AppBarLayout或者AppBarLayout的子类的时候返回true。之所以RadioGroup在向上滑动的时候会隐藏,向下滑动的时候会显示,是因为在onDependentViewChanged方法里,动态地根据dependency的top值改变RadioGroup的translationY值。
第二种实现方式
主要是根据onStartNestedScroll()和onNestedPreScroll()方法来实现的,开始滑动时,判断是否是垂直滑动,如果是返回true,返回true会接着调用onNestedPreScroll()等一系列方法。
1 | //判断滑动的方向 我们需要垂直滑动 |
在onNestedPreScroll()方法里面,根据显示规则来决定是否显示target,即向上滑动时,如果滑动的距离超过target的高度并且当前是可见的状态下,执行动画隐藏target;当前向下滑动并且View是不可见的情况下,执行动画显示target。
1 | //根据滑动的距离显示和隐藏footer view |
完整代码见FooterBehavior。
两种实现方法比较
第一种方法主要是重写layoutDependsOn和onDependentViewChanged这两个方法,在layoutDependsOn判断dependency是否是AppBarLayout的实现类,所以会导致child依赖于AppBarLayout,实现简单但是灵活性不是太强。
第二种方法主要是重写onStartNestedScroll和onNestedPreScroll这两个方法,判断是否是垂直滑动,是的话就进行处理,灵活性大大增强。
需要注意的是不管是第一种方法还是第二种,都需要重写带两个构造方法的函数。
仿虾米音乐的首页效果
效果如下:

这个页面从上到下大致可以分为searchbar、header、banner、list四个部分,还有一个部分bottom是一直在底部没有互动的,先暂时不管。这里将list定为愿意接受滑动事件的部分,这几个部分的依赖关系为:searchbar→header→banner→list。
List
先从依赖的根源开始写相应的behavior,即ListBehavior。从上面的gif图来看,初始位置是在searchbar、header、banner的下面的,当滑动到最上面的时候在header的下面,所以可以在onLayoutChild里,先确定能显示列表最大的时候的位置,用child.layout来确定宽和高。再通过setY把它放到初始位置。
1 |
|
这几个height都会在behavior构造的时候初始化。首先在onStartNestedScroll直接返回true,表示愿意接收滑动事件。然后在onNestedPreScroll开始处理滑动事件,这里需要根据list当前的位置和滑动的方向来判断是否需要消费这个滑动事件。代码如下:
1 |
|
在onInterceptTouchEvent中,当接受到DOWN事件时,重置一些状态。当列表滑到顶部的时候,需要断掉滑动。然后再次执行滑动,才能继续滑动效果。
1 |
|
Banner
Banner的思路就很简单,首先在layoutDependsOn里确定依赖关系。
1 |
|
然后在onDependentViewChanged里,根据dependency的位置来更新自己的位置。
1 |
|
Header
HeaderBehavior也先确定依赖关系:
1 |
|
然后再根据dependency的位置来更新自己的位置:
1 |
|
SearchBar
代码如下:
1 |
|
其实这个方案也不是唯一的,比如可以把header和banner当成一个child,然后根据位置信息控制banner的透明;愿意接受滑动事件的部分也可以不是list,是header或者其它。
参考资料:
gdutxiaoxu 自定义Behavior —— 仿知乎,FloatActionButton隐藏与展示
Xugter CoordinatorLayout系列(三):Behavior的实践