Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BottomSheet + ViewPager2 drag to hide not works

I got troubles and I think it is CoordinatorLayout's fault but not sure. I'm using ViewPager2 inside a ConstraintLayout and I use the CoordinatorLayout like BottomSheet. But when I drag to hide it not works good. I replaced the ViewPager2 by ViewPager and it works well. I hope you can help me.

This is my XML file:

    <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:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/bottom_sheet_behavior"
        app:behavior_hideable="false"
        app:behavior_peekHeight="60dp" >

        <androidx.viewpager2.widget.ViewPager2
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintDimensionRatio="4:3"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:background="#0000FF"/>
    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
like image 370
Oscar Hernandez Avatar asked Jan 26 '20 04:01

Oscar Hernandez


1 Answers

This can be solved by disabling the nested scrolling of the ViewPager2 RecyclerView; but since the RecyclerView can't be directly accessed through the ViewPager2 library. Then it can't be achieved in layout.

So, instead we can get that RecyclerView using java reflection as follows:

Java:

public static RecyclerView getRecyclerView(ViewPager2 viewPager) {
    try {
        Field field = ViewPager2.class.getDeclaredField("mRecyclerView");
        field.setAccessible(true);
        return (RecyclerView) field.get(viewPager);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return null;
}

Kotlin:

fun ViewPager2.getRecyclerView(): RecyclerView? {
    try {
        val field = ViewPager2::class.java.getDeclaredField("mRecyclerView")
        field.isAccessible = true
        return field.get(this) as RecyclerView
    } catch (e: NoSuchFieldException) {
        e.printStackTrace()
    } catch (e: IllegalAccessException) {
        e.printStackTrace()
    }
    return null
}

Then disable the nested scrolling:

Java:

RecyclerView recyclerView = getRecyclerView(viewPager);
if (recyclerView != null) {
    recyclerView.setNestedScrollingEnabled(false);
    recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); // Optional
}

Kotlin:

val recyclerView = viewPager.getRecyclerView()
recyclerView?.isNestedScrollingEnabled = false
recyclerView?.overScrollMode = View.OVER_SCROLL_NEVER // Optional

This works with me without setting the OverScrollMode, so, if it doesn't work with you can disable the OverScrollMode like above.

like image 186
Zain Avatar answered Sep 19 '22 16:09

Zain