Ahmad-Hamwi / TabSync

An Android lightweight synchronizer between (Views) RecyclerView & TabLayout, (Compose) LazColumn and TabRow.
Apache License 2.0
154 stars 13 forks source link

Does not work if recyclerview is inside nested scrollview #3

Closed agustinsivoplas closed 2 years ago

agustinsivoplas commented 2 years ago

Does not work if recyclerview is inside nested scrollview even if you have isNestedScrollingEnabled = true/ false

Ahmad-Hamwi commented 2 years ago

Hi. the sample provided in the repository explains how to implement the solution using nested RecyclerViews.

Could you provide more information about how have you implemented your solution? What parameters have you provided to the TabbedListMediator object?

Also, there's a Medium article demonstrating how it would work using a nested RecyclerView.

agustinsivoplas commented 2 years ago

The structure of my screen is

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:clipChildren="false"
    android:clipToPadding="false">

    <org.allinahealth.android.core.ui.widgets.StickyNestedScrollView
        android:id="@+id/foodMenuScrollContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:fillViewport="true"
        android:overScrollMode="never"
        android:scrollbars="none"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:orientation="vertical"
            android:paddingBottom="@dimen/food_menu_screen_padding_bottom">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/default_margin_medium"
                android:clipChildren="false"
                android:clipToPadding="false">

                <include
                    android:id="@+id/foodMenuHeader"
                    layout="@layout/layout_header_title"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="@dimen/default_margin_medium"
                    android:layout_marginEnd="@dimen/default_margin_medium"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintWidth_max="@dimen/max_screen_width_size" />

                <androidx.appcompat.widget.AppCompatTextView
                    android:id="@+id/foodMenuDietRestrictionsTextView"
                    style="@style/BodyText"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/default_margin"
                    android:text="@string/food_menu_diet_restrictions_message"
                    app:layout_constraintEnd_toEndOf="@+id/foodMenuHeader"
                    app:layout_constraintStart_toStartOf="@+id/foodMenuHeader"
                    app:layout_constraintTop_toBottomOf="@+id/foodMenuHeader"
                    app:layout_goneMarginTop="@dimen/default_margin_medium" />

                <com.google.android.material.chip.ChipGroup
                    android:id="@+id/foodMenuDietRestrictionsChipGroup"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/default_margin"
                    android:clickable="false"
                    android:focusable="false"
                    android:focusableInTouchMode="false"
                    android:overScrollMode="never"
                    app:layout_constraintEnd_toEndOf="@+id/foodMenuHeader"
                    app:layout_constraintStart_toStartOf="@+id/foodMenuHeader"
                    app:layout_constraintTop_toBottomOf="@+id/foodMenuDietRestrictionsTextView" />

                <androidx.constraintlayout.widget.ConstraintLayout
                    android:id="@+id/tabsContainerLayout"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/default_margin_medium"
                    android:tag="sticky"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/foodMenuDietRestrictionsChipGroup">

                    <com.google.android.material.tabs.TabLayout
                        android:id="@+id/foodMenuTabs"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:fadingEdgeLength="@dimen/default_margin_large_medium"
                        android:overScrollMode="never"
                        android:paddingStart="@dimen/default_padding_medium"
                        android:paddingEnd="@dimen/default_padding_medium"
                        android:requiresFadingEdge="horizontal"
                        android:scrollbars="none"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent"
                        app:layout_constraintWidth_max="@dimen/max_screen_width_size"
                        app:tabMode="scrollable"
                        app:tabSelectedTextColor="@color/tab_selected_text_color"
                        app:tabTextAppearance="@style/Heading3.Black"
                        app:tabTextColor="@color/tab_unselected_text_color" />

                    <View
                        android:id="@+id/foodMenuTabsSeparatorView"
                        android:layout_width="0dp"
                        android:layout_height="@dimen/separator_height"
                        android:background="@color/separator_gray"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@+id/foodMenuTabs"
                        app:layout_constraintWidth_max="@dimen/max_screen_width_size" />
                </androidx.constraintlayout.widget.ConstraintLayout>

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/foodMenuItemListRecyclerView"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:overScrollMode="never"
                    android:paddingBottom="@dimen/default_padding"
                    app:layout_constraintEnd_toEndOf="@+id/foodMenuHeader"
                    app:layout_constraintStart_toStartOf="@+id/foodMenuHeader"
                    app:layout_constraintTop_toBottomOf="@+id/tabsContainerLayout"
                    tools:itemCount="5"
                    tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                    tools:listitem="@layout/list_item_food_menu_item_content" />
            </androidx.constraintlayout.widget.ConstraintLayout>
        </LinearLayout>
    </org.allinahealth.android.core.ui.widgets.StickyNestedScrollView>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/foodMenuReviewOrderButton"
        style="@style/PrimaryFilledButtonRoundedCorner"
        android:layout_width="0dp"
        android:layout_marginStart="@dimen/default_margin_medium"
        android:layout_marginTop="@dimen/default_margin_medium"
        android:layout_marginEnd="@dimen/default_margin_medium"
        android:layout_marginBottom="@dimen/default_margin_medium"
        android:text="@string/review_order"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintWidth_max="@dimen/max_screen_width_size" />
</androidx.constraintlayout.widget.ConstraintLayout>
tabbedListMediator = TabbedListMediator(foodMenuItemListRecyclerView, foodMenuTabs, categoriesIndex)
tabbedListMediator.attach()

The idea is achieve this behaviour with a sticky tabs: untitled

But If I remove the StickyNestedScroll works. So, I think something in StickyNestedScroll is blocking some scroll event or not propagating the scroll to the recycler view?

StickyNestedScroll is just a NestedScrollView

untitled

Thanks for your help!

All the best

Ahmad-Hamwi commented 2 years ago

Have you tried android:nestedScrollingEnabled="true" on the parent RecyclerView that's holding the categories, and android:nestedScrollingEnabled="false" on child RecyclerView that's holding the food items?

agustinsivoplas commented 2 years ago

Have you tried android:nestedScrollingEnabled="true" on the parent RecyclerView that's holding the categories, and android:nestedScrollingEnabled="false" on child RecyclerView that's holding the food items?

I am using just one recycler view to create categories and items using differents view types and view holders in the same adapter

agustinsivoplas commented 2 years ago

I have fixed removing the StickyNestedScrollView and using a coordinator layout to snap the tabs

Ahmad-Hamwi commented 2 years ago

@agustinsivoplas That's great! Though, I guess the issue should be opened on StickyNestedScrollView's maintainers, not on this library, because the way I implemented the synchronizer is that it heavily relies on the scrolling events that's being received to it. So any view blocking the events will probably make the synchronizer to break. And since the Coordinator layout make no problem in propagating the scroll events, I guess it's in the end not the synchronizer's issue.

Good luck with your app development, It really looks nice! I'm glad that this library helped you after all. Feel free to open any issues regarding the synchronizer, and have a nice day my friend.

agustinsivoplas commented 2 years ago

Thanks for your help and suggestions! Great library, thanks for share with the community!

All the best

😄