Search code examples
androidandroid-recyclerviewandroid-coordinatorlayout

RecyclerView inside CoordinatorLayout scrolls before Toolbar is colapsed


I have an image and a recyclerview, and I would like it to scroll as if they were inside a NestedScrollView. But I also want my RecyclerView to recycle the views (not to load everything like in a listview).

To achieve that, I am using a CoordinatorLayout. But it's not working the way that I need. The RecyclerView is scrolling even when the CollapsibleToolbar is not collapsed.

Could anyone help me figure out what I am doing wrong? I have tried everything I read here on StackOverflow, nothing worked.

I already tried android:nestedScrollingEnabled="true" and "false" as suggested in similar questions. Didn't work.

androidx version: androidx.appcompat:appcompat:1.4.1

<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ToVisitFragment"
android:id="@+id/to_visit_container">

<androidx.coordinatorlayout.widget.CoordinatorLayout
    android:id="@+id/to_visit_coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/to_visit_app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:visibility="visible"
        app:elevation="0dp">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/to_visit_collapsing_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/to_visit_map"
                    style="@style/WorldMap"
                    android:contentDescription="@string/world_map"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />

            </androidx.constraintlayout.widget.ConstraintLayout>
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/to_visit_regions_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="80dp"
        android:clipToPadding="false"
        android:orientation="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:listitem="@layout/item_region" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:id="@+id/to_visit_button_add"
    style="@style/MyFloatingActionButton"
    android:contentDescription="@string/desc_add_city"
    android:backgroundTint="@color/purple"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />
 </androidx.constraintlayout.widget.ConstraintLayout>

EDIT

After @BenjyTec mentioned the recyclerView item layout file, I found the problem. I have another recyclerView inside the item. I had set isScrollContainer to false, but didn't set nestedScrollView to false on the inner recyclerView.

Here is the working code:

item layout:

    <TextView
        android:id="@+id/region_title"
        style="@style/Title"
        android:layout_marginStart="24dp"
        android:layout_marginTop="24dp"
        android:text="América Latina"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/region_country_list"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:isScrollContainer="false"
        android:nestedScrollingEnabled="false"
        android:layout_marginTop="10dp"
        android:layout_marginStart="24dp"
        android:layout_marginEnd="24dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/region_title"
        tools:listitem="@layout/item_country"/>

Coordinator Layout:

<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/to_visit_coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/to_visit_app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:visibility="visible"
        app:elevation="0dp">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/to_visit_collapsing_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_collapseMode="pin">

                <ImageView
                    android:id="@+id/to_visit_map"
                    android:layout_width="0dp"
                    android:layout_height="0dp"
                    android:scaleType="fitCenter"
                    android:src="@drawable/map_world"
                    android:paddingStart="10dp"
                    android:paddingEnd="10dp"
                    android:background="@color/grey_200"
                    android:contentDescription="@string/world_map"
                    app:layout_constraintDimensionRatio="h,16:11"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />

            </androidx.constraintlayout.widget.ConstraintLayout>
                
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/to_visit_regions_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="80dp"
        android:clipToPadding="false"
        tools:listitem="@layout/item_region"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/to_visit_button_add"
        style="@style/MyFloatingActionButton"
        android:contentDescription="@string/desc_add_city"
        android:backgroundTint="@color/purple"
        android:layout_gravity="bottom|end"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Solution

  • I've created a small sample app to test out the combination of RecyclerView and CollapsingToolbarLayout. The result I get from the sample app looks like this:

    Screenrecording

    Is that what you want to achieve? If yes, and it still does not work, you might want to show your layout file of the RecyclerView items, as the culprit might be there.

    Also, your root ConstraintLayout might be useless. If you only need it to place the FloatingActionButton, you can also achieve the same thing by using CoordinatorLayout attribute layout_gravity, as shown below.

    Below is the layout for the sample app:

    <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/to_visit_coordinatorLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/to_visit_app_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/transparent"
            android:visibility="visible"
            app:elevation="0dp">
    
            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:id="@+id/to_visit_collapsing_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">
    
                <ImageView
                    android:id="@+id/to_visit_map"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:scaleType="centerCrop"
                    android:src="@drawable/photo"
                    app:layout_collapseMode="parallax"
                    app:layout_collapseParallaxMultiplier="0.7" />
    
            </com.google.android.material.appbar.CollapsingToolbarLayout>
        </com.google.android.material.appbar.AppBarLayout>
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/to_visit_regions_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingBottom="80dp"
            android:clipToPadding="false"
            android:orientation="vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />
    
    
        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/to_visit_button_add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="Description"
            android:layout_margin="@dimen/fab_margin"
            android:layout_gravity="bottom|end" />
    
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
    

    And the layout file for the RecyclerView items:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp">
    
        <TextView
            android:id="@+id/tvAnimalName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"/>
    
    </LinearLayout>