RecyclerView inside a ScrollView/NestedScrollView does not scroll properly - android

I have a layout which has a CardView and a FloatingActionButton associated with it. There is a list of replies below the CardView (which is a RecyclerView). Sometimes the CardViews' height is greater than the screen, so I have used layout_height="wrap_content" for the CardView and wrapped the whole LinearLayout inside a ScrollView.
However, this causes a problem(since it is a scrolling view inside a ScrollView) while scrolling the items of the RecyclerView. As suggested in some of the questions and answers posted, I have used both the NestedScrollView and the android:nestedScrollingEnabled="true" tag but the scrolling in the RecyclerView is still bad.
Here is my Layout file -
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context="com.example.forum.reply.ReplyActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/reply_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:titleTextColor="#android:color/white"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="true"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="#+id/topic_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="#dimen/card_margin"
android:paddingLeft="#dimen/card_margin"
android:paddingRight="#dimen/card_margin"
android:paddingTop="#dimen/card_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingEnd="#dimen/card_margin"
android:paddingStart="#dimen/card_margin">
<android.support.v7.widget.AppCompatTextView
android:id="#+id/topic_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:textAppearance="#style/TextAppearance.AppCompat.Title"/>
<android.support.v7.widget.AppCompatTextView
android:id="#+id/topic_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="#style/TextAppearance.AppCompat.Body1"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<ProgressBar
android:id="#+id/reply_progressbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
android:visibility="visible"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/list_of_replies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="#+id/reply_to_topic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:clickable="true"
android:src="#drawable/ic_reply_white_24dp"
app:layout_anchor="#id/topic_card"
app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>
Here are some images -

When you have multiple scrolling Views in your layout (eg. RecyclerView + ScrollView) and when you scroll while in your recyclerView, the recyclerView scrolls with the parent Scrollview. this causes jitters in RecyclerView. You can avoid this jitter by the following.
You can add android:nestedScrollingEnabled="false"
to your RecyclerView in XML or recyclerView.setNestedScrollingEnabled(false);
to your RecyclerView in Java.

If you want to support devices older than api 21 then you should use
ViewCompat.setNestedScrollingEnabled(mRecyclerView, false);
in your Activity/Fragment

You have to do multiple tasks:
put your recyclerview inside a android.support.v4.widget.NestedScrollView instead of normal ScrollView
set your recyclerview android:nestedScrollingEnabled="true" in layout XML file
to support devices older than API 21 then you should use ViewCompat.setNestedScrollingEnabled(mRecyclerView, false) in your code
set your RecyclerView height to android:layout_height="wrap_content" (or width if it is horizontal!)

Besides Setting the android:nestedScrollingEnabled="false" you need to make sure that the parent of the RecyclerView is a android.support.v4.widget.NestedScrollView
I had troubles that the RecyclerView did not measure properly (on big screens) when it was in a standard ScrollView

if you want to scroll RecyclerView inside ScrollView and ScrollView prevents from scrolling RecyclerView (in API 16 this occurred) you should use android.support.v4.widget.NestedScrollView
instead of ScrollView and also you must set
nestedScrollView.setNestedScrollingEnabled(false);
by this way you can prevent from scrolling nestedScrollView when you scroll RecyclerView.
hope this help some one

I have this problem ,solving it with :
custom ScrollView and override onInterceptTouchEvent to return false.
hope it's help someone/

Related

How to have two recyclerview (horizontal first then vertical) in the same Layout with smaooth scroll

I have two recyclerview (horizontal first, then vertical) in the same layout, I want the two to scroll up together so I used NestedScrollView but it come with some serious scrolling issue. It lag and cause crash some time.
I already saw some folks suggested using nestedScrollingEnabled = "false" in the RecyclerView but I already tried and nothing still no result.
Any idea on how to achieve this ?
Here's the xml btw
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/appbar"
android:clipToPadding="false"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/stories_recycler_view"
storiesData="#{viewModel.stories}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="#layout/item_story" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/posts_recycler_view"
feedListData="#{viewModel.entries}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical"
app:stackFromEnd="true"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:paddingBottomSystemWindowInsets="#{true}"
app:paddingTopSystemWindowInsets="#{true}"
app:reverseLayout="true"
tools:listitem="#layout/item_text_post" />
</LinearLayout>
post your XML code and what did you mean by both scrolling up? horizontal views don't go upwards
<androidx.core.widget.NestedScrollView
android:id="#+id/nested_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout>
...
Add `android:nestedScrollingEnabled="true"` in both Recyclerview Tag...<br>
...
</LinearLayout>
<androidx.core.widget.NestedScrollView/>

RecyclerView inside NestedScrollView inside SwipeRefreshLayout doesn't scroll smoothly

Here's my layout.
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/activity_main_swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_marginBottom="45dp"
android:layout_height="wrap_content">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusableInTouchMode="true">
<Button
android:layout_width="300dp"
android:layout_height="100dp"
android:id="#+id/noob_button"
android:text="haha" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/noob_button"
android:orientation="vertical"
android:clipToPadding="false"
android:scrollbars="vertical" />
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
This is all inside RelativeLayout.
I have set recyclerview.setNestedScrol..(false);
It still hangs and if I set fixed height of the RecyclerView it doesn't hang. It scrolls but the scroll is not smooth.
You do not actually need a RecyclerView inside a NestedScrollView. As far as I have understood your question, you need a Button and a RecyclerView under the button. So you might consider adding the Button as the header of the RecyclerView which is neater implementation.
If you are thinking of adding a header in your RecyclerView please see my answer here on how this can be achieved.
I have explained how a footer can be added. The same rule applies for adding a header view as well. Please let me know if you have any further questions regarding this.

Multiple horizontal RecyclerView inside NestedScrollView steal focus

Actually I'm currently working for a AndroidTV app. I have multiple horizontal RecyclerView right to left inside a NestedScrollView like that image.
Problem is that when I scroll more towards left, then focus moves to different list or different view which is not good.
I don't want the focus to change. If the list reaches to the end, then focus should remain at same position.
I tried :
android:descendantFocusability="blocksDescendants"
android:focusableInTouchMode="true" //in parent layout
But it didn't work..
Can anyone help me out ??
Not solved
Try changing your ScrollView to NestedScrollView. A reason behind this is
**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.
**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
This will help you to determine which layout is being focused.
You can use below structure for nested scroll
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:clickable="false"
android:orientation="vertical">
<android.support.v4.widget.NestedScrollView
android:id="#+id/scroll_search_all"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isScrollContainer="false"
android:nestedScrollingEnabled="false" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isScrollContainer="false"
android:nestedScrollingEnabled="false" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</FrameLayout>
I hope this will help!
Try using this one code in your recycleview section 2:
android:layoutDirection="rtl"

RecyclerView part of ScrollView

I have a RecyclerView as the bottom view, along with some other views on top:
I want to scroll the entire view (1), not just the RecyclerView (2).
I have managed to get it to work, but not flawlessly. XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/toolbar" />
<android.support.v4.widget.NestedScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
...
<View
style="#style/Divider"
android:layout_marginBottom="16dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerViewNote"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
Two problems:
Scrolling in the recyclerview isn't smooth, in the sense that when I lift up my finger, the scrolling stops. No accelerated scroll, or whatever you call it.
When I remove items from the recyclerview, its height remains the same. Meaning I have empty space where the images once was.
I have tried with your example
Scrolling in the recyclerview isn't smooth, in the sense that when I
lift up my finger, the scrolling stops. No accelerated scroll, or
whatever you call it.
Even I noticed that. I think there are some restrictions when you use nested scrolling as it has to handle both scrolls.
When I remove items from the recyclerview, its height remains the
same. Meaning I have empty space where the images once was.
The white space is because of the padding you have applied to the linear layout of recyclerview. Event though you remove all items from recyclerview the padding of parent linear layout remains same and so is the whitespace.
use nestedScrollView
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.NestedScrollView>

Horizontal RecyclerView inside vertical ScrollView

So I have a horizontal RecyclerView inside a vertical ScrollView. Everything inside my layout is displayed fine and it all scrolls in the directions I want and it does it smoothly.
The only problem I have, is that the RecyclerView is below some other content in the ScrollView and when the RecyclerView is partially visible, it will line the bottom of the RecyclerView with the bottom of the screen on start-up. This means that the content above the RecyclerView is pushed off the screen.
Does anyone know why this happens, and how I can fix it?
Here is a simple layout that does what I just described. You don't even need to populate the RecyclerView, it will still do it.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="500dp"
android:background="#fff"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#000"/>
</LinearLayout>
</ScrollView>
Turns out this issue was reported to Google here Issue - 81854
According to Google it is working as intended. The problem is the fact that RecyclerView has focusableInTouchMode set to true. To fix the problem I set focusableInTouchMode and focusable to true on the top-most view of the ScrollView.
Below is the fix for the code sample I provided in the original question:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="500dp"
android:background="#fff"
android:focusableInTouchMode="true"
android:focusable="true"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#000"/>
</LinearLayout>
</ScrollView>
I have been looking for a solution for a long time. In the end, I decided by accident. In your activity, find the ScrollView and add a touch listener for it. Everything will work as it should
ScrollView scroll = findViewById(R.id.scroll);
scroll.setOnTouchListener((view, motionEvent) -> {
return false;
});

Categories

Resources