自定义BottomNavigationViewBehavior时onNestedScroll未触发,需实现滚动隐藏
哈哈,这个需求我前段时间刚折腾过!Android框架确实没有开箱即用的方案,但借助CoordinatorLayout的Behavior机制,我们自己写几行代码就能完美实现。下面给你一步步拆解:
1. 调整布局结构
首先确保你的布局根节点是CoordinatorLayout,并且给BottomNavigationView绑定自定义Behavior。完整布局示例如下:
<androidx.coordinatorlayout.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"> <!-- 你的滚动内容容器,比如RecyclerView/NestedScrollView --> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> <!-- 底部导航栏,绑定自定义Behavior --> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_nav" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" app:menu="@menu/your_bottom_menu" app:layout_behavior=".BottomNavHideBehavior"/> </androidx.coordinatorlayout.widget.CoordinatorLayout>
注意:如果还在用旧的support包,把androidx替换成android.support即可,但更建议迁移到AndroidX。
2. 编写自定义Behavior类
这个类是核心,用来监听滚动事件,控制BottomNavigationView的显示/隐藏:
Java版本
import android.content.Context; import android.util.AttributeSet; import android.view.View; import androidx.coordinatorlayout.widget.CoordinatorLayout; import com.google.android.material.bottomnavigation.BottomNavigationView; import androidx.core.view.ViewCompat; public class BottomNavHideBehavior extends CoordinatorLayout.Behavior<BottomNavigationView> { public BottomNavHideBehavior(Context context, AttributeSet attrs) { super(context, attrs); } // 只监听垂直方向的滚动 @Override public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, BottomNavigationView child, View directTargetChild, View target, int axes, int type) { return axes == ViewCompat.SCROLL_AXIS_VERTICAL; } // 根据滚动方向处理导航栏的显示隐藏 @Override public void onNestedScroll(CoordinatorLayout coordinatorLayout, BottomNavigationView child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type, int[] consumed) { super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed); // 向上滚动:隐藏导航栏(translationY设为自身高度,移出屏幕) if (dyConsumed > 0 && child.getTranslationY() < child.getHeight()) { child.animate().translationY(child.getHeight()).setDuration(200).start(); } // 向下滚动:显示导航栏(translationY设为0,回到原位) else if (dyConsumed < 0 && child.getTranslationY() > 0) { child.animate().translationY(0).setDuration(200).start(); } } }
Kotlin版本
import android.content.Context import android.util.AttributeSet import android.view.View import androidx.coordinatorlayout.widget.CoordinatorLayout import com.google.android.material.bottomnavigation.BottomNavigationView import androidx.core.view.ViewCompat class BottomNavHideBehavior(context: Context, attrs: AttributeSet) : CoordinatorLayout.Behavior<BottomNavigationView>(context, attrs) { override fun onStartNestedScroll( coordinatorLayout: CoordinatorLayout, child: BottomNavigationView, directTargetChild: View, target: View, axes: Int, type: Int ): Boolean { return axes == ViewCompat.SCROLL_AXIS_VERTICAL } override fun onNestedScroll( coordinatorLayout: CoordinatorLayout, child: BottomNavigationView, target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, type: Int, consumed: IntArray ) { super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed) when { // 向上滚动隐藏 dyConsumed > 0 && child.translationY < child.height -> { child.animate().translationY(child.height.toFloat()).setDuration(200).start() } // 向下滚动显示 dyConsumed < 0 && child.translationY > 0 -> { child.animate().translationY(0f).setDuration(200).start() } } } }
3. 注意事项
- 你的滚动容器(RecyclerView/NestedScrollView)必须支持嵌套滚动,这两个控件默认已经支持,如果是自定义滚动View,需要实现
NestedScrollingChild接口。 - 动画时长可以根据需求调整,200ms是比较自然的过渡速度,你可以改成其他数值。
- 确保依赖了Material组件库,不然BottomNavigationView会找不到:
implementation 'com.google.android.material:material:1.9.0'
内容的提问来源于stack exchange,提问作者eight
相关产品推荐
相关产品推荐

