BottomSheet中多相邻NestedScrollView仅首个可滚动的问题求助
解决BottomSheet中仅首个NestedScrollView可触发滚动的问题
我之前也碰到过一模一样的坑!当BottomSheet里放了两个带可见性切换的NestedScrollView时,默认的BottomSheetBehavior只会在初始化时绑定第一个可滚动的子View,后续切换显示的那个ScrollView就没法触发BottomSheet的滚动交互了。下面是几个我亲测有效的解决思路:
方法1:自定义BottomSheetBehavior,动态识别可见的滚动View
默认Behavior只会在启动时找一次可滚动的子View,我们可以重写它的逻辑,让它能动态追踪当前可见的NestedScrollView:
class DynamicBottomSheetBehavior<V : View>(context: Context, attrs: AttributeSet) : BottomSheetBehavior<V>(context, attrs) { override fun findScrollingChild(view: View): View? { // 优先找当前可见的NestedScrollView if (view is NestedScrollView && view.visibility == View.VISIBLE) { return view } // 递归遍历子布局 if (view is ViewGroup) { for (i in 0 until view.childCount) { val scrollingChild = findScrollingChild(view.getChildAt(i)) if (scrollingChild != null) { return scrollingChild } } } return null } // 切换ScrollView可见性时,调用这个方法重新绑定 fun refreshScrollingChild() { view?.let { val newScrollChild = findScrollingChild(it) if (newScrollChild != currentScrollingChild) { currentScrollingChild?.setOnScrollChangeListener(null) currentScrollingChild = newScrollChild currentScrollingChild?.setOnScrollChangeListener(scrollListener) } } } }
之后在你切换两个NestedScrollView可见性的代码里,调用refreshScrollingChild()就能让Behavior重新绑定当前可见的滚动View了。
方法2:给BottomSheet根布局加触摸事件拦截
如果不想自定义Behavior,也可以在BottomSheet的根ViewGroup里手动处理触摸事件,帮可见的ScrollView“接管”BottomSheet的滚动逻辑:
bottomSheetRoot.setOnTouchListener { _, event -> val activeScrollView = if (scrollView1.visibility == View.VISIBLE) scrollView1 else scrollView2 when (event.action) { MotionEvent.ACTION_DOWN -> { // 让当前可见的ScrollView获取触摸焦点 activeScrollView.requestFocus() false } MotionEvent.ACTION_MOVE -> { val behavior = BottomSheetBehavior.from(bottomSheetRoot) // 当ScrollView滑到顶部还继续下拉时,让BottomSheet响应滚动 if (activeScrollView.scrollY == 0 && event.y > 0) { behavior.setState(BottomSheetBehavior.STATE_DRAGGING) true } else { false } } else -> false } }
这个方法比较轻量,适合快速解决简单场景的问题。
方法3:合并布局,用单个NestedScrollView包裹切换内容
如果两个切换的内容不需要同时显示,最省心的办法是把它们放到同一个NestedScrollView里,只切换内部子布局的可见性:
<androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- 第一组内容 --> <LinearLayout android:id="@+id/content_group1" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="visible"> <!-- 你的内容 --> </LinearLayout> <!-- 第二组内容 --> <LinearLayout android:id="@+id/content_group2" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="gone"> <!-- 你的内容 --> </LinearLayout> </LinearLayout> </androidx.core.widget.NestedScrollView>
这种方式不需要额外写逻辑,BottomSheet始终只识别这一个ScrollView,自然不会有滚动失效的问题。
你可以根据自己项目的复杂度选合适的方案,我个人更推荐第一种自定义Behavior的方式,扩展性更强,能适配更复杂的场景。
内容的提问来源于stack exchange,提问作者Nik.206
相关产品推荐
相关产品推荐

