Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView scroll dosen't work with NestedScrollView

I have a layout where I have a NestedScrollView containing an Image, multiple buttons and a RecycleView.

When I say recycleView.smoothScrollToPosition or recycleView.scrollToPosition() it doesn't do anything at the moment. Refuse to scroll even a pixel. If I remove the NestedScrollView it works fine, but in case I lose the scrolling effect on the surrounding areas.

Does any of you met with this problem before?

<?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"
android:fitsSystemWindows="true"
tools:context="world.the.rule.com.testtollbarstuff.ScrollingActivity">

<android.support.design.widget.AppBarLayout
    android:id="@+id/app_bar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/app_bar_height"
    android:fitsSystemWindows="true"
    android:orientation="vertical"
    android:theme="@style/AppTheme.AppBarOverlay">


    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:layout_collapseMode="none"
        app:popupTheme="@style/AppTheme.PopupOverlay" />


</android.support.design.widget.AppBarLayout>

<android.support.design.widget.CollapsingToolbarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fitsSystemWindows="true"
    app:contentScrim="?attr/colorPrimary"
    app:layout_scrollFlags="scroll">

    <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"
            app:layout_collapseMode="parallax">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:adjustViewBounds="true"
                android:clickable="true"
                android:src="@drawable/mock_image" />

            <include layout="@layout/content_scrolling" />

        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CollapsingToolbarLayout>

like image 797
narancs Avatar asked Dec 21 '16 09:12

narancs


People also ask

How do I prevent NestedScrollView from scrolling if body is small?

The problem can be solved by moving the SliverAppBar into the CustomScrollView and not use the NestedScrollView at all.

What is the difference between NestedScrollView and ScrollView?

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.

How do I stop NestedScrollView scrolling?

setnestedscrollingenabled set it to false. try this one add property in recyclerview android:descendantFocusability="blocksDescendants" .

How do you load all items in RecyclerView without scrolling?

It's pretty simple, simply set the RecyclerView 's height to wrap_content . That's right.


2 Answers

If you just want smooth scroll then no custom scrolling required as I mentioned earlier in some other thread.

Add lines as below when ever you want to start smooth scroll

appBarLayout.setExpanded(false, /*true if animation required else false*/true);
recyclerView.smoothScrollToPosition(position);

Additional Info

Additionally, I don't see any RecyclerView in your layout and chances are there you have kept it in LinearLayout which is again part of CollapsingToolbarLayout. I have absolutely no idea why you have kept RecyclerView as part of CollapsingToolbarLayout. I will give a layout (simplified one) which I am using.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:id="@+id/app_bar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:expanded="true"
            app:layout_behavior="com.company.app.custom.CustomRecyclerScrollBehavior">

            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/collapsing_toolbar"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:contentScrim="?attr/colorPrimary"
                app:expandedTitleMarginEnd="64dp"
                app:expandedTitleMarginStart="48dp"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">

                <FrameLayout
                    android:id="@+id/header_frame"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layout_collapseMode="parallax"
                    app:layout_collapseParallaxMultiplier="0.8">

                    <com.company.app.custom.CustomViewPager
                        android:id="@+id/view_pager"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        app:calculation="height"
                        app:height_ratio="@integer/product_listitem_img_width_ratio"
                        app:width_ratio="@integer/product_listitem_img_height_ratio" />

                    <com.company.app.custom.CustomImageView
                        android:id="@+id/img_stock_layer"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:adjustViewBounds="true"
                        android:scaleType="fitXY"
                        android:src="@color/transparent_app_black"
                        android:visibility="gone"
                        app:calculation_type="height"
                        app:ratio_height="@integer/product_listitem_img_width_ratio"
                        app:ratio_width="@integer/product_listitem_img_height_ratio" />

                    <com.inneex.www.customfonts.FontTextView
                        android:id="@+id/lbl_out_of_stock"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center"
                        android:text="@string/out_of_stock"
                        android:textColor="?android:attr/textColorPrimaryInverse"
                        android:textSize="13sp"
                        android:visibility="gone"
                        app:customFont="@string/font_ss_semibold" />

                    <LinearLayout
                        android:id="@+id/ll_page"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="bottom|center_horizontal"
                        android:orientation="horizontal"
                        android:paddingBottom="@dimen/inspire_detail_oval_margin_bottom" />

                </FrameLayout>

                <android.support.v7.widget.Toolbar
                    android:id="@+id/main_toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/toolbar_height"
                    android:background="?attr/colorPrimary"
                    app:layout_anchor="@id/header_frame"
                    app:layout_collapseMode="pin"
                    app:title="">

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:orientation="horizontal">

                        <com.inneex.www.customfonts.FontTextView
                            android:id="@+id/lbl_toolbar_product_name"
                            android:layout_width="0dp"
                            android:layout_height="wrap_content"
                            android:layout_gravity="center"
                            android:layout_weight="1"
                            android:ellipsize="end"
                            android:lines="1"
                            android:maxLines="1"
                            android:minLines="1"
                            android:textColor="?android:attr/textColorPrimary"
                            android:textSize="18sp"
                            app:customFont="@string/font_ss_semibold" />

                    </LinearLayout>
                </android.support.v7.widget.Toolbar>
            </android.support.design.widget.CollapsingToolbarLayout>

        </android.support.design.widget.AppBarLayout>

        <ImageView
            android:id="@+id/img_back"
            android:layout_width="@dimen/toolbar_height"
            android:layout_height="@dimen/toolbar_height"
            android:layout_gravity="top|start"
            android:scaleType="fitXY"
            android:src="@drawable/back"
            app:layout_collapseMode="parallax" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    </android.support.design.widget.CoordinatorLayout>

    <include
        layout="@layout/listitem_product_detail_buy_cheap"
        android:layout_width="match_parent"
        android:layout_height="@dimen/product_detail_button_buy_cheap_height"
        android:layout_alignParentBottom="true"
        android:layout_gravity="bottom" />

</RelativeLayout>

FrameLayout with id header_frame is responsible for big toolbar which will collapse on scrolling. Toolbar with id main_toolbar is responsible for collapsed view of toolbar. RecyclerView is the below AppBarLayout. ImageView is for back button that will be displayed once collapsed Toolbar is displayed.

For reference, to make scroll smooth I have added CustomRecyclerScrollBehavior which I talked earlier with you. This is what it is

import android.content.Context;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by jimitpatel on 13/12/16.
 */

public class CustomRecyclerScrollBehavior extends AppBarLayout.Behavior {

    private Map<RecyclerView, RecyclerViewScrollListener> scrollListenerMap = new HashMap<>(); //keep scroll listener map, the custom scroll listener also keep the current scroll Y position.


    public CustomRecyclerScrollBehavior() {
    }

    public CustomRecyclerScrollBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     *
     * @param coordinatorLayout
     * @param child The child that attached the behavior (AppBarLayout)
     * @param target The scrolling target e.g. a recyclerView or NestedScrollView
     * @param velocityX
     * @param velocityY
     * @param consumed The fling should be consumed by the scrolling target or not
     * @return
     */
    @Override
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
        if (target instanceof RecyclerView) {
            final RecyclerView recyclerView = (RecyclerView) target;
            if (scrollListenerMap.get(recyclerView) == null) {
                RecyclerViewScrollListener recyclerViewScrollListener = new RecyclerViewScrollListener(coordinatorLayout, child, this);
                scrollListenerMap.put(recyclerView, recyclerViewScrollListener);
                recyclerView.addOnScrollListener(recyclerViewScrollListener);
            }
            scrollListenerMap.get(recyclerView).setVelocity(velocityY);
            consumed = scrollListenerMap.get(recyclerView).getScrolledY() > 0; //recyclerView only consume the fling when it's not scrolled to the top
        }
        return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
    }

    private static class RecyclerViewScrollListener extends RecyclerView.OnScrollListener {
        private int scrolledY;
        private boolean dragging;
        private float velocity;
        private WeakReference<CoordinatorLayout> coordinatorLayoutRef;
        private WeakReference<AppBarLayout> childRef;
        private WeakReference<CustomRecyclerScrollBehavior> behaviorWeakReference;

        public RecyclerViewScrollListener(CoordinatorLayout coordinatorLayout, AppBarLayout child, CustomRecyclerScrollBehavior barBehavior) {
            coordinatorLayoutRef = new WeakReference<>(coordinatorLayout);
            childRef = new WeakReference<>(child);
            behaviorWeakReference = new WeakReference<>(barBehavior);
        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            dragging = newState == RecyclerView.SCROLL_STATE_DRAGGING;
        }

        public void setVelocity(float velocity) {
            this.velocity = velocity;
        }

        public int getScrolledY() {
            return scrolledY;
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            scrolledY += dy;

            if (scrolledY <= 0 && !dragging && childRef.get() != null && coordinatorLayoutRef.get() != null && behaviorWeakReference.get() != null) {
                //manually trigger the fling when it's scrolled at the top
                behaviorWeakReference.get().onNestedFling(coordinatorLayoutRef.get(), childRef.get(), recyclerView, 0, velocity, false);
            }
        }
    }
}

This class is used for maintaining scroll speed for RecyclerView in nested scrolls. It's fling has been changed over here

Hope this works out for you!

like image 70
Jimit Patel Avatar answered Oct 10 '22 07:10

Jimit Patel


do this

recycleView.smoothScrollToPosition(80);

later , not inside onCreate method , either use delayed thread or in another overide method.

example :

     new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
              recycleView.smoothScrollToPosition(80);
        }
     }, 150);
like image 37
yanivtwin Avatar answered Oct 10 '22 08:10

yanivtwin