Funny Solution that Makes BottomSheetDialog Support ViewPager with NestedScrollingChilds
Recently we have a special feature which need a complicated composition in BottomSheetDialog
. That architecture is 1.) create a BottomSheetDialog, 2.) add ViewPager
as major content, 3.) each page has its own RecyclerView
.
This is easy implementation (at our first opinion) until we found the scrolling behavior on RecyclerView of 2nd page is gone after swiping to the next page. And than, my colleague Samuel investigated and found out this solution.
Update in Jan 5, 2019 from Mo Li
viewPager.getChildAt(viewPager.getCurrentItem()) doesn’t works for me. it may not return the view of current selected page.
My solution:
@VisibleForTesting
override fun findScrollingChild(view: View): View? {
return if (view is ViewPager) {
view.focusedChild?.let { findScrollingChild(it) }
} else {
super.findScrollingChild(view)
}
}
Thanks Mo Li’s comment and improve this solution.
How does BottomSheetDialog support NestedScrollingChild
BottomSheetDialog has a default BottomSheetBehavior
, so it can handle nested scrolling view without any extra implementation. It will get reference of nested scrolling view on onLayoutChild()
,
public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
....
mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
}
Why scrolling is gone after swiping to another page of ViewPager
As previous introduction, BottomSheetBehavior only get the reference on onLayoutChid(), that means, BottomSheetBehavior doesn’t get callback from ViewPager when changing its current page, so it won’t update the reference.
Here we can refer the source code of BottomSheetBehavior.
How to update reference of the scrolling child of BottomSheetBehavior
Even there are so many solutions in Stack Overflow, our member chosen a different solution to resolve this issue: to extend default BottomSheetBehavior, and then add a public method to update scrolling child reference when ViewPager changes its current item.
ViewPagerBottomSheetBehavior extends BottomSheetBehaviors, and there is a new method, updateScrollingChild()
, which calls findScrollingChild() to update the reference. And more, because original findScrollingChild() only support ViewGroup, we need to override original updateScrollingChild() to support ViewPager, from line 24 ~ 30.
And then we set customized bottom-sheet-behavior when creating BottomSheetDialog, and call updateScrollingChild()
when onPageSelected()
Because we need to access the package-private variable, mNestedScrollingChildRef
, we have to put ViewPagerBottomSheetBehavior inside package android.support.design.widget
. That why I call the solution funny.