多说无益,先上效果图img\material-design
这个效果其实是和SegmentFault
的首页效果是一样的。
来由
前几天有人问我这样的效果如何实现,有何思路,我的第一反应就是使用Behavior
来实现这个效果,使用Behavior
实现此效果比自定义View实现此效果绝对要简单很多,之后找时间了实现了这个效果。
思路
用过ToolBar + CoordinatorLayout + AppBarLayout
的人应该知道这三者组合使用再设置合适的参数(没用过的人赶紧去看看吧,或者看我的Demo也可以哟),就可以实现滑动隐藏显示ToolBar
,因此这部分的效果Android
使用Behavior
已经替我们实现好了,没必要再去费神了,而且它的效果也蛮不错。
接下来我们要考虑的就是如何实现在滑动的时候也隐藏底部的BottomNavigation
,既然前面我已经说过用Behavior
来实现此效果,因此我们需要自定义一个Behavior
来实现滑动隐藏BottomNavigation
。
撸代码
在前面一篇文章自定义Behavior实现快速返回效果(没看过的请先看看)中我已经介绍了自定义Behavior
的相关知识,这里就不再赘述了。
先来看看ToolBar
滑动隐藏的代码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<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/holo_blue_dark"
app:title="ToolBar Title"
app:titleTextColor="@android:color/white"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
上面属性设置中app:layout_scrollFlags="scroll|enterAlways"
这个是必须要有,否则话滑动的时候ToolBar
是不会滑动的。
那滑动隐藏BottomNavigation
的这个Behavior
该如何实现呢?其实很简单,我们在滑动列表的时候可以看到当ToolBar
往上滑的时候BottomNavigation
会同时往下滑,因此这里我可以把ToolBar
作为BottomNavigation
的依赖,ToolBar
往上滑动多少BottomNavigation
就同时往下滑动多少(这里我实现时保证了两者高度一致)。
既然知道了依赖关系也知道了滑动方向和滑动距离,再实现Behavior
就简单多了,代码如下: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
35public class BottomNavigationViewBehavior extends CoordinatorLayout.Behavior<View> {
public BottomNavigationViewBehavior() {
}
public BottomNavigationViewBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
((CoordinatorLayout.LayoutParams) child.getLayoutParams()).topMargin = parent.getMeasuredHeight() - child.getMeasuredHeight();
return super.onLayoutChild(parent, child, layoutDirection);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
//因为Behavior只对CoordinatorLayout的直接子View生效,因此将依赖关系转移到AppBarLayout
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
//得到依赖View的滑动距离
int top = ((AppBarLayout.Behavior)((CoordinatorLayout.LayoutParams)dependency.getLayoutParams()).getBehavior()).getTopAndBottomOffset();
//因为BottomNavigation的滑动与ToolBar是反向的,所以取-top值
ViewCompat.setTranslationY(child, -top);
return false;
}
}
上面的代码中获取依赖视图AppBarLayout
的滑动距离时需要注意几点:
- 通过
AppBarLayout.getTranslationY()
无法获取到正确的滑动距离 - 通过
AppBarLayout.getTop()
无法获取到正确的滑动距离 - 最后查看源码后发现通过
AppBarLayout.Behavior.getTopAndBottomOffset()
可以获得正确的滑动距离值
现在Behavior
实现了,我们再来看完整的布局文件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<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/holo_blue_dark"
app:title="ToolBar Title"
app:titleTextColor="@android:color/white"
app:layout_scrollFlags="scroll|enterAlways"/>
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_light"
app:tabTextColor="@android:color/white"
app:tabGravity="center"
app:tabIndicatorColor="@android:color/white"
app:tabSelectedTextColor="@android:color/holo_red_dark"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/holo_blue_dark"
android:layout_gravity="bottom"
app:menu="@menu/bottom_menus"
app:layout_behavior="cn.ittiger.stickynavigation.behavior.BottomNavigationViewBehavior"
/>
</android.support.design.widget.CoordinatorLayout>
对于布局中的ToolBar
和BottomNavigationView
也可以换成其他任意View
来实现滑动隐藏效果。
Demo的完整代码在这 github地址
原创文章,转载请出处注明。
下面是我的个人公众号,欢迎关注交流