Android nestedScrollView + tabLayout + viewPager + recyclerView layout sliding conflict and make paging3 load more invalid alternative solutions

Posted by andrewburgess on Wed, 09 Mar 2022 10:36:52 +0100

Recently, there was a demand that the customer wanted to add a drop-down refresh function. I see, this is not very simple. The SmartRefreshLayout control is introduced, and the layout can be written with a few swipes.

This is the main layout:

<?xml version="1.0" encoding="utf-8"?>
<com.ggh.michat.widget.PagingRecyclerViewContainer 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:background="@color/white"
    android:orientation="vertical">

    <androidx.core.widget.NestedScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        android:scrollbars="none">

        <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">

                <com.google.android.material.tabs.TabLayout
                    android:id="@+id/chat_square_tab"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentStart="true"
                    app:tabGravity="center"
                    app:tabIndicatorFullWidth="false"
                    app:tabIndicatorHeight="0dp"
                    app:tabMode="scrollable"
                    app:tabRippleColor="@android:color/transparent" />

                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentEnd="true"
                    android:layout_centerVertical="true"
                    android:layout_marginEnd="@dimen/dp_10"
                    android:src="@drawable/icon_select" />

            </RelativeLayout>

            <cn.bingoogolapple.bgabanner.BGABanner
                android:id="@+id/banner"
                android:layout_width="match_parent"
                android:layout_height="150dp"
                android:layout_marginStart="@dimen/dp_10"
                android:layout_marginTop="@dimen/dp_10"
                android:layout_marginEnd="@dimen/dp_10" />

            <androidx.viewpager2.widget.ViewPager2
                android:id="@+id/viewPager"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/dp_10"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
</com.ggh.michat.widget.PagingRecyclerViewContainer>

This is the recyclerView sub layout:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content_tv"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.scwang.smartrefresh.layout.SmartRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.scwang.smartrefresh.layout.header.ClassicsHeader
            android:layout_width="match_parent"
            android:layout_height="50dp" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:nestedScrollingEnabled="false" />

    </com.scwang.smartrefresh.layout.SmartRefreshLayout>

</FrameLayout>

After writing, the test is, uh, very good. There's no problem. It's over after writing.
...

The next day, open the familiar console and,???? All the data was loaded at once, and the paging function failed. Then I started the journey of finding bug s. It was found that the layout of NestedScrollView+ViewPager+RecyclerView led to the height of RecyclerView being increased all the time, which led to paging3 mistaking that the user had slid to the bottom, and then began to load the content of the next page until all the data was loaded..

According to the principle of solving bugs when encountering bugs, skillfully open the search engine and input: "NestedScrollView nested RecyclerView page loading invalid solution", start browsing the content and find the method. It is RecyclerView to add a Header, but the layout here is a tabLayout and a banner. Adding a Header is not appropriate. Then continue to find the method and find it again, It is to intercept the sliding event of NestedScrollView, and then distribute the event to the child View when sliding to the bottom. As soon as I see that this is feasible, I start my own series of operations.

After writing the test (the interception code will not be displayed if it is very watery), the sliding operation is OK, very good, but the sliding up! tabLayout and banner are not jacked up during fast sliding.. Failed.

Then I suddenly remembered that I looked at the CoordinatorLayout layout of the first line of code, thought that this layout combined with AppBarLayout seemed to completely solve my current problem, and then started a new wave of code..

It is feasible to test skillfully after writing! Completely solved the previous sliding conflict problem and paging3 failure problem!!

Below is the revised Code:

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white">

    <com.google.android.material.appbar.AppBarLayout
        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">

            <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">

                    <com.google.android.material.tabs.TabLayout
                        android:id="@+id/chat_square_tab"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentStart="true"
                        app:layout_scrollFlags="scroll"
                        app:tabGravity="center"
                        app:tabIndicatorFullWidth="false"
                        app:tabIndicatorHeight="0dp"
                        app:tabMode="scrollable"
                        app:tabRippleColor="@android:color/transparent" />

                    <ImageView
                        android:id="@+id/select"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_alignParentEnd="true"
                        android:layout_centerVertical="true"
                        android:layout_marginEnd="@dimen/dp_10"
                        android:padding="@dimen/dp_10"
                        android:src="@drawable/icon_select"
                        app:layout_scrollFlags="scroll" />

                </RelativeLayout>

                <cn.bingoogolapple.bgabanner.BGABanner
                    android:id="@+id/banner"
                    android:layout_width="match_parent"
                    android:layout_height="150dp"
                    android:layout_marginStart="@dimen/dp_10"
                    android:layout_marginTop="@dimen/dp_10"
                    android:layout_marginEnd="@dimen/dp_10"
                    app:layout_scrollFlags="scroll" />

            </LinearLayout>
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginEnd="@dimen/dp_10"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content_tv"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.scwang.smartrefresh.layout.SmartRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.scwang.smartrefresh.layout.header.ClassicsHeader
            android:layout_width="match_parent"
            android:layout_height="50dp" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </com.scwang.smartrefresh.layout.SmartRefreshLayout>

</FrameLayout>

This is the test chart:

You can use the layout of CoordinatorLayout + AppBarLayout to replace the previous layout to achieve alternative solutions!

End

Topics: Android viewpager