如何在BottomSheetDialogFragment内的ViewPager2上启用拖动?

ATE*_*TES 6 java android android-layout android-recyclerview

BottomSheetDialogFragment在片段布局和打开STATE_EXPANDED模式上有一个很好的垂直拖动状态。它recyclerview里面有一个,垂直拖动可以在底部工作表上工作,但recyclerview由于滚动事件而无法工作。recyclerview当到达列表顶部并且仍然向上滚动以折叠底部工作表时,底部工作表拖动事件如何工作而不是滚动事件?

BottomSheetDialogFragment 层次结构:

FragmentRootLinearLayout -> ...BottomLinearLayout... -> ViewPager2 -> RecyclerView
Run Code Online (Sandbox Code Playgroud)

BottomSheetDialogFragment xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/BookInfoFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/tool_sheet_bg"
    android:orientation="vertical"
    app:layout_behavior="@string/bottom_sheet_behavior"
    app:behavior_hideable="true"
    android:clickable="true"
    android:focusable="true">

    <LinearLayout
        android:id="@+id/tabs_linear_layout"
        style="@style/ThemeSettingsRowContainer"
        android:layout_width="match_parent"
        android:layout_height="550dp"
        android:layout_marginTop="15dp"
        android:background="@drawable/xml_rounded_corner_bg2"
        android:clickable="true"
        android:focusable="true"
        android:paddingTop="0dp"
        android:paddingBottom="0dp">

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/book_loading_tablayout"
            android:layout_width="match_parent"
            android:layout_height="50dp" />

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/book_loading_viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clickable="true"
            android:focusable="true" />

    </LinearLayout>

</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

编辑:问题出在 ViewPager2 上,当我将其更改为 ViewPager 时,拖动效果很好。同样的问题:BottomSheet + ViewPager2 拖动隐藏不起作用

Zai*_*ain 9

问题是我们需要禁用 上的嵌套滚动ViewPager2,但是android:nestedScrollingEnabled="false"不起作用,因为它ViewPager2在内部运行RecyclerView,具有嵌套滚动的效果。

因此,您需要禁用 的嵌套滚动ViewPager RecyclerView

主要问题是 默认情况下无法访问RecyclerViewof 。ViewPager2

2022 年 2 月更新

添加一种更好的方法来访问 of ,RecyclerViewViewPager2不是使用反射:

科特林:

viewPager2.children.find { it is RecyclerView }?.let {
    (it as RecyclerView).isNestedScrollingEnabled = false
}
Run Code Online (Sandbox Code Playgroud)

爪哇:

for (int i = 0; i < viewPager2.getChildCount(); i++) {
    View child = mViewPager.getChildAt(i);
    if (child instanceof RecyclerView)
        ((RecyclerView) child).setNestedScrollingEnabled(false);
}
Run Code Online (Sandbox Code Playgroud)

这应该可行,但如果仍然遇到问题,请尝试禁用以下内容的过度滚动模式RecyclerView

// Kotlin
recyclerView?.overScrollMode = View.OVER_SCROLL_NEVER // Optional
// Java
recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); // Optional
Run Code Online (Sandbox Code Playgroud)

预览:


带着反思----

您可以使用java 反射来访问它。

RecyclerView这需要知道可以在定义类中找到的名称字段,ViewPager2该字段是mRecyclerView

将其组合在一个辅助函数中:

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;
}
Run Code Online (Sandbox Code Playgroud)

然后您可以禁用嵌套滚动,如下所示:

RecyclerView recyclerView = getRecyclerView(viewPager);
if (recyclerView != null)
    recyclerView.setNestedScrollingEnabled(false);
Run Code Online (Sandbox Code Playgroud)
recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
Run Code Online (Sandbox Code Playgroud)

对于 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
}
Run Code Online (Sandbox Code Playgroud)

及用法:

val recyclerView = viewPager.getRecyclerView()
recyclerView?.isNestedScrollingEnabled = false
recyclerView?.overScrollMode = View.OVER_SCROLL_NEVER // Optional
Run Code Online (Sandbox Code Playgroud)