Search code examples
androidandroid-fragmentsscrollandroid-viewpagerandroid-nestedscrollview

NestedScrolling inside a Viewpager inside a BottomSheetDialog


Short version:

How do I set the NestedScrollingChild of a NestedScrollingParent with multiple number of such child.

Long version

I implemented a BottomSheetDialogFragment whose layout consists of a ViewPager, and the adapter of this viewpager contains a RecyclerView.

Now, the issue is, since a NestedScrollingParent which in this time the coordinator layout of the bottomsheet supports only one direct NestedScrollingChild, only the first fragment of the adapter can be nest-scrolled.

What I mean is, whenever setAdapter is called on the viewpager, the first item supports nested scrolling. But after I change the page, the new page now does not scroll. Then when I go back to the previous page, it still supports scrolling.

Also, I noticed that if the fragment or the page that can scroll is destroyed, the succeeding page now can scroll, which means that the latter page becomes the scrolling child of the bottom sheet. The problem is that page which now gained the scrolling ability is not the current item but a preceding one (my adapter must maintain 3 fragments).

Summary:

After setAdapter

  • fragment 0 can scroll
  • then after changing page to fragment 1, fragment 1 cannot scroll
  • but switching to fragment 2, then going back to fragment 1 allows fragment 1 to scroll (since fragment 0 is destroyed I guess)

Solution

  • After digging into the source code, I found that the problem lies on a faulty algorithm used in finding the NestedScrollingChild of the bottomsheet (folks at Google did not take into account the possiblity of a ViewPager inside the bottomsheet).

    See the method here: findScrollingChild()

    What this method does is it will return the first NestedScrollingChild it encounters on a given view (the bottomsheet in this case), which in the case of a viewpager with 3 pages, the one preceding the current page. Also, this method is triggered during the layout phase of the children of the CoordinatorLayout wrapper of the bottomsheet.

    With this in mind, one can devise many solutions including subclassing the behavior itself.

    Also, one can limit the NestedScrollingChild inside the viewpager by adding and removing one instance of such child (remove from the old page, then add in the current page), which is what I did. You can do this inside setPrimaryItem of the adapter or on a OnPageChangeListener. Just be sure to call requestLayout on the coordinator layout of the bottomsheet. (This solution depends on the kind of layout/structure of the pager adapter so I won't post my exact solution).