Paging library when used inside a nestedscrollview loads all data - android

I am using paging library to load data and populate my recyclerview which is placed inside a nestedscrollview. But it is like, pagination works automatically until all the data fetched from API. I know this is because of the nestedscrollview. But unfortunately my layout needs scrollview as i have a top section other than recyclerview in this fragment.
This is my layout
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
//have a layout here which scrolls with recyclerview
<Recyclerview />
</ConstraintLayout>
</NestedScrollView>
Everything works fine when i do not use nestedscrollview. There is an open issue in googlesamples git repo regsrding this problem.
https://github.com/googlesamples/android-architecture-components/issues/215
Is anyone have idea how can we implement pagination when a recyclerview is inside a scrollview with pagination library from Android jetpack. I know we can implement traditional kind of pagination attaching listener to nestedscrollview, but i am looking to implement pagination with architecture component library.
https://developer.android.com/topic/libraries/architecture/paging/

Using the below code will solve the issue.
Here is the view hierarchy:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar_layout"
android:background="#color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:titleEnabled="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Put here elements that you need above the recycler view -->
</LinearLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<!-- RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Note: Be sure that you have given id to CoordinatorLayout and AppBarLayout so that it will retain scroll position on the back stack.

The problem is recyclerview inside nested scrolview. Paging library has nothing to do with it. The behavior would be same if you try to load data on scroll listener of recyclerview.

The paging library does not work well with nestedScroolView. So you have to change your NesteScrollView to ScroolView with android:nestedScrollingEnabled="true", something like this:
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="true"
>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
//have a layout here which scrolls with recyclerview
<Recyclerview />
</ConstraintLayout>
</ScrollView>

Related

BottomSheetBehavior with ViewPager2 can't be scrolled down by nested RecyclerView scroll

I have a view that acts like BottomSheetBehavior and this view has ViewPager2 inside. Each ViewPager2's page is a vertical RecyclerView. The issue is that BottomSheet doesn't scroll down when current vertical RecyclerView (which is a page of ViewPager) can't scroll vertically anymore. Everything works file when instead of ViePager I have only one vertical RecyclerView.
The temporary solution is to wrap ViewPager with NestedScrollView but it's horrible for performance and has it's own bugs.
The original layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/core"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#C7C7C7"
tools:context=".MainActivity">
<LinearLayout
android:id="#+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:elevation="8dp"
android:orientation="vertical"
app:behavior_hideable="true"
app:behavior_peekHeight="300dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tab_layout"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_gravity="center_horizontal"
app:tabGravity="center"
app:tabMode="scrollable" />
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
[Here's how it looks (sorry for the gif quality)]
I've found a solution for this case, I set isNestedScrollingEnabled = false for inner RecyclerView so that BottomSheetBehavior finds another scrolling view
viewPager.children.find { it is RecyclerView }?.let {
(it as RecyclerView).isNestedScrollingEnabled = false
}
BottomSheetBehaviour only detects the first scrollable view. So it is always recommended to use only one scrollable view inside of it.
For More information check this answer bottomsheetbehavior-with-two-recyclerview
And this one also Scroll not working for multiple RecyclerView in BottomSheet
If you really want to have the two scrollable views I recommend you to take a look at this library also AndroidSlidingUpPanel

RecyclerView doesnot scroll when not nested in NestedScrollView but is in the same LinearLayout

I am using the following layout, but unable to get the RecyclerView to scroll(it is not visible on the screen when using this layout, scrolling stops till the NestedScrollView).
I can scroll up to the NestedScrollView and the CollapsingToolbar to collapse, if I remove the entire NestedScrollView then I get the RecyclerView to scroll.
If I keep the linear layout without the NestedScrollView, only the RecyclerView scrolls, the rest of the layout is fixed.
I have also added app:layout_behavior="#string/appbar_scrolling_view_behavior" to the RecyclerView, and have kept the RecyclerView out of the NestedScrollView.
If I add the RecyclerView inside the NestedScrollView, the RecyclerView does not appear.
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.MainFragment">
<!-- android.support.design.widget.AppBarLayout here
with a android.support.design.widget.CollapsingToolbarLayout
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<!-- more layout code here -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/large_text"/>
</RelativeLayout>
<View
android:id="#+id/separator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/colorAccent" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerViewListOfData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="#layout/recycler_view"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</LinearLayout>
Ok, if you want to add RecyclerView inside NestedScrollView add this line into RecyclerView in xml file app:layoutManager="LinearLayoutManager".
Example
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/your_recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="LinearLayoutManager"/>
</android.support.v4.widget.NestedScrollView>
Then in your SomeActivity.java file where you populate RecyclerView put this line recyclerView.setNestedScrollingEnabled(false); before you setting adapter to RecyclerView.
Example
RecyclerView recyclerView=(RecyclerView)findViewById(R.id.your_recyclerview);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setAdapter(yourAdapter);
I solved it by nesting RecyclerView inside the NestedScrollView and updating the support library for recyclerview
I was using com.android.support:recyclerview-v7:23.0.1
as of Android Support Library, revision 23.2.0 (February 2016)
(refer revision archive here)
Changes for v7 RecyclerView library:
RecyclerView now has an opt-in feature called AutoMeasure which allows RecyclerView.LayoutManager to easily wrap content or
handle various measurement specifications provided by the parent of
the RecyclerView. It supports all existing animation capabilities of
the RecyclerView.
If you have a custom RecyclerView.LayoutManager, call setAutoMeasureEnabled(true) to start using the new AutoMeasure API.
All built-in RecyclerView.LayoutManager objects enable auto-measure by
default.
RecyclerView.LayoutManager no longer ignores some RecyclerView.LayoutParams settings, such as MATCH_PARENT in the scroll
direction.
Note: These lifted restrictions may cause unexpected behavior in your
layouts. Make sure you specify the correct layout
parameters.
Using com.android.support:recyclerview-v7:23.4.0 solves the problem of nested recyclerview not appearing in nested scroll view

Nested scrollview inside gridview place is taking only somepart

I have:
1.Coordinator layout
2.appbar layout (child of Coordinator layout)
3.Collapsing toolbar layout (child of app bar)
4.NestedScrollView (child of coordinator)
I want to put a grid view inside NestedScrollView so that user can scroll over the entire screen space.
My problem is that currently the gridview occupies a small portion of the NestedScrollView and not full space of NestedScrollView and scrolls inside that portion,like in this image:
As you can see my gridview height is limited upto only that highlighted portion in sky blue color, i want that to occupy the entire screen space below that image(which is my Collapsing toolbar).i tried different ways but nothing works out.
my xml file is:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:id="#+id/app_bar"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="196dp"
android:background="#3f51b5"
app:contentScrim="#color/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="#+id/imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/index"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<GridView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="1dp"
android:layout_marginRight="1dp"
android:id="#+id/gridView"
android:verticalSpacing="1dp"
android:horizontalSpacing="1dp"
android:numColumns="2"
android:stretchMode="columnWidth"/>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/ic_dialog_email" />
GridView already has scrolling built in, so it conflicts with a NestedScrollView. You should be using a RecyclerView with a GridLayoutManager and appbar_scrolling_view_behavior layout behavior in place of the NestedScrollView.
well i had the same issue , the following worked for me.
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:fillViewport="true">
It is true, that GridView conflicts with the NestedScrollView and the correct solution would be to use the RecyclerView, but I needed a quick workaround with such setup and came across a solution using a custom class extending the GridView:
https://gist.github.com/jiahuang/2591977
Then you just have to replace your GridView with the custom class and set the parameter of NestedScrollView as in Apoorv's answer:
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:fillViewport="true">
Apoorv Singh's answer helped me, but not fully. You can put a GridView inside a NestedScrollView, but only the 1st row will show up. You need to add the android:fillViewport="true" inside the NestedScrollView definition in order for everything to display properly.
But, when I scroll down, it doesn't scroll past the bottom of the screen. I have a grid with 10 rows, there are multiple rows not on screen, but I cannot scroll down to view them now.
Answer:
This worked for me now. Use RecyclerView with GridLayoutManager instead of GridView. As Recycler view is compatible with Collapsing toolbar as well. And when you use RecyclerView inside NestedScrollView, it works well. Everything sizes correctly, as well as scrolls correctly.
Inside NestedScrollView add this one line code
android:fillViewport="true"

Scroll behavior in nested RecyclerView with horizontal scroll

I have to create vertical RecyclerView with nested horizontal RecyclerView in every item. Everything is within CoordinatorLayout. When I scroll by tapping outside nested RecyclerView toolbar hides, but when I scroll parent Recycler by tapping on nested one toolbar stays.
Any help would be appreciated.
Here is my xml layouts:
main_activity.xml:
<android.support.design.widget.CoordinatorLayout
...>
<FrameLayout
android:id="#+id/fragment_frame"
...
android:fitsSystemWindows="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<android.support.design.widget.AppBarLayout
...
android:fitsSystemWindows="true"
android:id="#+id/appbar_layout">
<include layout="#layout/toolbar"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
Here is toolbar.xml :
<android.support.v7.widget.Toolbar
android:id="#+id/main_toolbar"
...
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|enterAlways">
<TextView .../>
</android.support.v7.widget.Toolbar>
fragment.xml:
<android.support.v7.widget.RecyclerView
...
android:scrollbars="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
And recycler_view_item.xml:
<RelativeLayout ...>
<TextView .../>
<!-- fixme(CullyCross) fix bug with hiding toolbar -->
<android.support.v7.widget.RecyclerView
...
android:scrollbars="horizontal"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
</RelativeLayout>
Thanks,
Anton
As requested here is the solution I found good enough so far:
In my case I have a nestedScrollView with 4 RecyclerViews set to scroll horizontally inside. For each of those RecyclerViews I have done this programatically:
restaurantsRecylerView.setHasFixedSize(true);
restaurantsRecylerView.setNestedScrollingEnabled(false);
You probably don't want the fixedSize, not sure if it will make any difference, my list is always 25 so I can use that for performance. After having done this I can scroll without issues even when I touch on the recyclerViews
Hope it helps
Try with RecyclerView inside android.support.v4.widget.NestedScrollView.
<android.support.v4.widget.NestedScrollView
android:id="#+id/nScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Set other views of your Layout -->
</android.support.v4.widget.NestedScrollView>
Also try with different layout_scrollFlags in Toolbar and
RecylerView.setNestedScrollingEnabled(false); // set it true or false as per requirement
We can achieve this in XML
android:nestedScrollingEnabled="false"

RecyclerView drawing offscreen, can't scroll bottom item into view

Using Design Support Library 22.2.1, with the following View hierarchy:
<DrawerLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
<TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
app:tabGravity="fill"
app:tabMode="scrollable" />
</AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior">
<!-- Fragments replaced here -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CustomDashboardView
android:layout_width="match_parent"
android:layout_height="120dp" />
<ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Tab Fragments go here -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CustomEmptyErrorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</ViewPager>
</LinearLayout>
</FrameLayout>
</CoordinatorLayout>
<NavigationView
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:fitsSystemWindows="true" />
</DrawerLayout>
I run into this problem where the RecyclerView's height is larger than the visible area in which it should be contained, so it looks like the RecyclerView is drawing offscreen, and it is impossible to scroll the last item in the RecyclerView into full view. There is also no movement regarding the Toolbar nor TabLayout (although a layout_behaviour is applied to the FrameLayout).
I had reported this as a bug, but ol' Banesy has stated this is working as intended. If that is the case, how can I avoid this intended behviour in favour of a RecyclerView that respects layout_height="match_parent" and draws its items within the visible screen? https://code.google.com/p/android/issues/detail?id=182391
UPDATE: now with Design Support v23, it's not looking good at all. I've narrowed this down to the Design Support lib itself (i.e. updating RecyclerView, appcompat, whatever else to v23 while leaving Design Support v22.2.1 yields the same problem as described above). So the new look, the CustomDashboardLayout and RecyclerView have gone AWOL, hopefully this isn't working as intended either:
I've managed to fix this on v23 and found a workaround for v22.2.1. The fact between the versions the behaviour is quite different leads me to believe "working as intended" isn't the whole truth.
v23 fix: CustomDashboardLayout above the ViewPager was causing the problem, when it wasn't forced to visibility="gone" the ViewPager wasn't being added to hierarchy at all. With it gone, the ViewPager is added and the RecyclerView sizes its height correctly.
v22.2.1 workaround: the v23 fix has no affect on v22.2.1, the workaround is to set layout_marginBottom="?attr/actionBarSize" on the RecyclerView.
Glad that's over anyway.
I also had the same problem even with the api level 26 today with this view hierarchy -
<android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.AppBarLayout>
<android.support.design.widget.CollapsingToolbarLayout>
<FrameLayout>
<android.support.v4.view.ViewPager/>
<TextView/>
</FrameLayout>
<android.support.v7.widget.Toolbar>
<TextView/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView/>
</android.support.design.widget.CoordinatorLayout>
After spending the whole day I felt that somehow the RecyclerView is not able to calculate the proper height. I arrived on this conclusion as when I swipe the ViewPager the RecyclerView was showing the last item correctly. So I added a ViewTreeObserveron the ViewPager in the activity and requested the RecyclerView to redraw itself. This solved my problem.
val obs = pager?.viewTreeObserver
obs?.addOnGlobalLayoutListener {
recyclerView?.requestLayout()
recyclerView?.invalidate()
}

Categories

Resources