Behavior实现滑动隐藏ToolBar与BottomNavigation

多说无益,先上效果图img\material-design

图片名称

这个效果其实是和SegmentFault的首页效果是一样的。

Demo github地址戳这里

来由

前几天有人问我这样的效果如何实现,有何思路,我的第一反应就是使用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
35
public 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的滑动距离时需要注意几点:

  1. 通过AppBarLayout.getTranslationY()无法获取到正确的滑动距离
  2. 通过AppBarLayout.getTop()无法获取到正确的滑动距离
  3. 最后查看源码后发现通过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>

对于布局中的ToolBarBottomNavigationView也可以换成其他任意View来实现滑动隐藏效果。

Demo的完整代码在这 github地址


原创文章,转载请出处注明。

下面是我的个人公众号,欢迎关注交流

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×