正确地处理BottomSheet
中ViewPager
的滑动事件。
最终效果
需要开发一个如下样式的弹窗,上拉可以全屏。
Xpop是一个优秀的弹窗库,而且解决了嵌套滑动问题,可是不能上拉全屏。
使用BottomSheetDialog
可以满足需求,并且可以通过设置peekHeight
来动态调整弹窗的初始高度,符合当前业务需求。
Android开发之BottomsheetDialogFragment的使用_神话2009的博客-CSDN博客_bottomsheetdialogfragment
底部弹出抽屉BottomSheetDialogFragment,圆角背景,去除层叠,百分比设置高度【总结】_锟钢的博客-CSDN博客_bottomsheetdialogfragment圆角
当BottomSheetDialog
内的布局是ViewPager
的时候,会有滑动冲突问题。
具体表现为只有第一个tab下的RecycleView可以正确的滑动,其他tab页的滑动处理全部失效了。
BottomSheetBehavior+ViewPager+多RecyclerView 滑动冲突(滑动弹出隐藏)终极解决方案 - 简书 (jianshu.com)
Android ViewPager with RecyclerView works incorrectly inside BottomSheet - Stack Overflow
android - Scroll not working for multiple RecyclerView in BottomSheet - Stack Overflow
可以确定是BottomSheetBehavior
没有正确处理子view的滑动事件导致的。
BottomSheetDialogFragment + ViewPager+Fragment+RecyclerView 滑动问题_张海龙_China的博客-CSDN博客
因为BottomSheetBehavior的findScrollingChild方法并没有有关ViewPager 更新查找子元素view的东西,所以它只能拿到一个页面去滑动,那么就需要对BottomSheetBehavior进行修改,这样的话就需要自己定义BottomSheetDialog:
@VisibleForTesting
View findScrollingChild(View view) {
if (ViewCompat.isNestedScrollingEnabled(view)) {
return view;
}
if (view instanceof ViewPager) {
ViewPager viewPager = (ViewPager) view;
View currentViewPagerChild = viewPager.getChildAt(viewPager.getCurrentItem());
// View currentViewPagerChild = ViewPagerUtils.getCurrentView(viewPager);
if (currentViewPagerChild == null) {
return null;
}
View scrollingChild = findScrollingChild(currentViewPagerChild);
if (scrollingChild != null) {
return scrollingChild;
}
} else if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
for (int i = 0, count = group.getChildCount(); i < count; i++) {
View scrollingChild = findScrollingChild(group.getChildAt(i));
if (scrollingChild != null) {
return scrollingChild;
}
}
}
return null;
}
将ViewPager
替换为ViewPager2
确实可以解决部分滑动冲突问题,但是并没有彻底解决。
具体表现为RecyclerView区域滑动则不会将滑动事件抛给父View处理。滑动事件全部被 RecyclerView
消费掉,滑动弹出和关闭功能消失了。
导致这个问题的原因也很简单,我们的滑动事件在 RecyclerView
加入前,都是由 BottomSheetBehavior
来消费的,当我们加入 RecyclerView
这种可滑动控件后,滑动事件都被其消费,这与 ViewPager
无关。
多数情况下我们需要
RecyclerView
消费事件(滑动),但我们同时希望当RecyclerView
滑动到顶部时,将事件又重新交给Behavior
消费,这样就可以做到,列表在顶部时滑动开启/关闭弹出框。
现象如下:
只点击TabLayout
才可以正确响应滑动事件,部分场景下可以满足需求。
将以上方法结合,使用ViewPager
,可以得到一个符合期望的弹窗。
ZYF99/BottomSheetTest: BottomSheetBehavior+ViewPager冲突解决+回弹效果+速度调节 (github.com)
laenger/ViewPagerBottomSheet: Use ViewPagers in Bottom Sheets! (github.com)
JiangAndroidwork/BottomSheetViewPager (github.com)
ParkSangGwon/TedBottomPicker: TedBottomPicker is simple image picker using bottom sheet (github.com)