Nested RecyclerViews in CoordinatorLayout - android

I have a problem with a View hierarchy in the app I am working on right now.
One of the screens looks like this:
<CoordinatorLayout>
<AppBarLayout>
<Toolbar/>
</AppBarLayout>
<RecyclerView>
... items, some of which are horizontal Recyclers...
</RecyclerView>
</CoordinatorLayout>
The whole idea is to have the Toolbar parallax nicely when scrolling down the RecyclerView content.
The whole thing works rather nicely, but there is a problem with the mentioned parallax behavior (which is done with a custom AppBarLayout.ScrollingViewBehavior implementation).
There are two cases, depending on what item user focuses when scrolling:
If a normal child is focused, the whole thing works as expected - Toolbar parallaxes in and out.
If a Recycler-based child is focused, the content RecyclerView will scroll as expected, but the parallax behavior will not fire, leaving the layout in a weird mid-state.
Any idea why this is happening and how to get the correct behavior, aka the events being passed all the way up to the CoordinatorLayout?

For each of your sub-recyclerView's, you need to call
setNestedScrollingEnabled(false)
on that RecyclerView (you can do this from whatever viewholder you are using for your main recyclerview to create the sub ones). This is a currently known bug in nested scrolling. If I were to guess, I would say that it probably has something to do with the fact that nested scrolling layouts are not supposed to send nested scrolling notifiers to parents if they are scrolled in directions in which they do not have a scrolling axis, if that makes any sense.

Related

Nested Scrolling inside a Viewpager2 inside a BottomSheet

It's 2022, and I'm having the same issue with ViewPager2 that folks had with ViewPager (see NestedScrolling inside a Viewpager inside a BottomSheetDialog ) - 5 years ago.
Although I'm not using a BottomSheetDialogFragment, just a regular old bottom sheet (with a FragmentContainer).
ViewPager2 is a bit different in that it itself uses a horizontal RecyclerView. BottomSheetView.findScollingChild() sees this as the scrolling child!
So, the approach I took to solving this is:
added a page change listener to my ViewPager2 that gets the hosting
CoordinatorLayout, and calls requestLayout() on it after the page change.
copied the BottomSheetBehavior class that matches my current material components version (1.5) into my project, renamed it, and made findScrollingChild public.
subclassed that copy, and set the sub-class as the behavior on my sheet.
Why sub-class and not just change the findScrollingChild method directly? Well, this way it's relatively easy to update the copy of BottomSheetBehavior when we update our material components.
My implementation of findScrollingChild() in the sub-class checks specifically for a ViewPager2.
If it is, it gets child 0 of the ViewPager2 (the horizontal RecyclerView), and then uses recycler?.layoutManager?.findViewByPosition(pager.currentItem) as the view to then search for the scrolling child.
If the view is not a ViewPager2, it uses the same algorithm from the original findScrollingChild()
This basically works. I have a pager with 2 tabs, one containing a ScollView that has nested scrolling enabled, and one containing a RecyclerView. The bottom sheet expands as its scrolled, and then the contents of the nested child scroll down properly once the sheet is open.
The problem is if after the sheet has expanded if the finger gets lifted, then any attempt to scroll up causes the bottom sheet to close rather then scrolling up -- no matter how far it's been scrolled down. At least this is the case for the RecyclerView in the second tab, I don't have enough content in the first tab at the moment that it actually needs to scroll.
The sheet gets closed with the list still scrolled down several pages (or wherever you stopped scrolling). If however you scroll down -- even just a little bit -- scrolling up works again! And you can swipe a couple times and it will work - until it doesn't, and the sheet moves to the half expanded state.
I'm not sure where this behavior is coming from or how to resolve it. It doesn't happen when the bottom sheet has a direct RecyclerView (no ViewPager2 I'm the way).
I tried disabling swiping in the ViewPager2 thinking it might be interfering with touch events, but to no avail.

How to properly scroll nested-scrollview?

How to properly scroll to a position in nestedscrollview which is inside a coordinate layout? When I use scrollTo(), it seems like the view inside AppBarLayout is loosing the ability to scroll down when I scroll to the end of NestedScrollView and coming back to top. What I need to know is how to programtically scroll to a position in nestedscrollview without causing problem with the normal behavior of collapsing layout.
Issue is similar to what is mentioned in this post:
The Coordinator layout doesn't Scroll up for a specific position
There is a Gif attached along with the above question:
https://i.stack.imgur.com/uSGfX.gif
I have tried the solution in above link, but it is not working.

RecyclerView + NestedScrollView + BottomSheetBehavior = bad performance?

Using Support library 27.1.1. I have a NestedScrollView with BottomSheetBehavior. Inside the bottom sheet layout I have LinearLayout with a header view at the top, then a RecyclerView at the bottom. The RecyclerView is populated with 10-20 custom views with heavy onDraw methods.
The whole idea of having a RecyclerView was to avoid inflating these views, as they are quite heavy to render. I want these views to render as soon as they are scrolled into view (dragging the bottom sheet header). The problem is that all children of the RecyclerView are inflated/rendered immediately. I thought I could stop this from happening using a custom LinearLayoutManager but haven't succeeded thus far.
There are a few sources on the net, discussing this particular problem. However, in my case there are a few things that change the conditions.
The RecyclerView is used along with the BottomSheetBehavior. With a height of 0dp the sheet cannot be opened!
The height of the custom views is known to be half the view width.
Support Library 27.1.1 or later is targeted (most discussions on the net consider v23.2).
Q: Is it possible to get the RecyclerView to recycle its views when put inside a NestedScrollView with BottomSheetBehavior? Or would it be easier to somehow prevent the heavy onDraw in the child views?

Why RecyclerView items disappear immediately when using Transition API?

This is a question regarding the use of Android Transition API.
I am trying to animate the height change of a list, just like a dropdown menu.
I tried 2 approaches
Use a RecyclerView and animates its height change
Use a ScrollView > LinearLayout hierarchy and animates ScrollView's height.
The 2nd approach works perfectly.
But the 1st approach has a serious glitch - when the collapse transition starts, items disappear immediately.
By looking at the below GIF you can observe clearly the difference:
To be exact, items' visibility changes at the moment I change RecyclerView's LayoutParams, without waiting for the transition to finish, whatever it is expanding or collapsing
Code
I have created a minimal project on Github.
If you just want to look at the code, here is the MainActivity.
Question
Is it possible to achieve ScrollView's effect with a RecyclerView?
If yes, how?
My Idea is to do the transition of all the recycler view rows individual rather than the whole RecyclerView:
So when collapsing iterate through each ROW of a RecyclerView and do a transition. Remember to check for null if some rows are recycled they may return null. So after that collapse the whole recyclerView.
And like wise for the expanding do the same for the views.
This issue is cause by RecyclerView has many views with it but Scroll View has only one View nested in it.

Android: ScrollView vs NestedScrollView

What is the difference between ScrollView and NestedScrollView? Both of them, extend FrameLayout. I want to know in depth pros and cons of both of them.
NestedScrollView as the name suggests is used when there is a need for a scrolling view inside another scrolling view. Normally this would be difficult to accomplish since the system would be unable to decide which view to scroll.
This is where NestedScrollView comes in.
In addition to the nested scrolling NestedScrollView added one major functionality, which could even make it interesting outside of nested contexts: It has build in support for OnScrollChangeListener. Adding a OnScrollChangeListener to the original ScrollView below API 23 required subclassing ScrollView or messing around with the ViewTreeObserver of the ScrollView which often means even more work than subclassing. With NestedScrollView it can be done using the build-in setter.
Other than the advantages listed in the answers given, one more advantage of NestedScrollView over ScrollView is its compatibility with CoordinatorLayout. The ScrollView does not cooperate with the CoordinatorLayout. You have to use NestedScrollView to get "scroll off-screen" behaviour for the toolbar.
Toolbar will not collapse with Scrollview as child of CoordinatorLayout
NestedScrollView
NestedScrollView is just like ScrollView, but it supports acting as
both a nested scrolling parent and child on both new and old versions
of Android. Nested scrolling is enabled by default.
https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html
ScrollView
Layout container for a view hierarchy that can be scrolled by the
user, allowing it to be larger than the physical display. A
ScrollView is a FrameLayout, meaning you should place one child in it
containing the entire contents to scroll; this child may itself be a
layout manager with a complex hierarchy of objects
https://developer.android.com/reference/android/widget/ScrollView.html
NestedScrollView is just like ScrollView, but in NestedScrollView we can put other scrolling views as child of it, e.g. RecyclerView.
But if we put RecyclerView inside NestedScrollView, RecyclerView's smooth scrolling is disturbed. So to bring back smooth scrolling there's trick:
ViewCompat.setNestedScrollingEnabled(recyclerView, false);
put above line after setting adapter for recyclerView.
I think one Benefit of using Nested Scroll view is that the cooridinator layout
only listens for nested scroll events. So if for ex. you want the toolbar to scroll down when you scroll you content of activity, it will only scroll down when you are using nested scroll view in your layout. If you use a normal scroll view in your layout, the toolbar wont scroll when the user scrolls the content.
<androidx.core.widget.NestedScrollView android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
// your Layout xml code
</androidx.core.widget.NestedScrollView>

Categories

Resources