如何在 BottomSheetDialogFragment 中启用 ViewPager2 的拖动功能?

8

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

BottomSheetDialogFragment层次结构:

FragmentRootLinearLayout -> ...BottomLinearLayout... -> ViewPager2 -> RecyclerView

底部对话框片段的 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>

编辑: 问题在于ViewPager2,当我将其更改为ViewPager时,拖动工作正常。相同的问题:BottomSheet + ViewPager2 拖动隐藏不起作用


请在@ATES处添加您的XML代码。 - androidLearner
就像那样。 - ATES
当你到达列表顶部时,你试图将底部的表格向下拖动,但它没有折叠,而是回收视图仍然在滚动?我说得对吗?@ATES - androidLearner
是的,你说得对,RecyclerView 的 onScrollEvent 没有处理因为滚动从顶部结束的情况。 - ATES
2个回答

9
问题在于我们需要禁用 ViewPager2 上的嵌套滚动,但是 android:nestedScrollingEnabled="false" 不起作用,因为 ViewPager2 内部使用 RecyclerView 进行功能实现,而这会导致嵌套滚动的效果。

所以,您需要禁用 ViewPager RecyclerView 上的嵌套滚动。

主要问题在于默认情况下无法访问 ViewPager2RecyclerView

2022年2月更新

提供一种更好的方法来访问 ViewPager2RecyclerView,而不是使用反射:

Kotlin:

viewPager2.children.find { it is RecyclerView }?.let {
    (it as RecyclerView).isNestedScrollingEnabled = false
}

Java:

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

这应该可以正常工作,但如果仍然遇到问题,那么尝试禁用 RecyclerView 的过度滚动模式:

// Kotlin
recyclerView?.overScrollMode = View.OVER_SCROLL_NEVER // Optional
// Java
recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); // Optional

预览:


With Reflections ----

You can access it using java reflection.

And this requires to know the name field of the RecyclerView which can be found in the ViewPager2 definition class which is mRecyclerView

Combining that together in a helper function:

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;
}

Then you can disable the nested scrolling as follows:

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

For Kotlin users:

Extension function:

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
}

And usage:

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

谢谢,代码可以运行,但为什么在RecyclerView上向上滚动不起作用? - ATES
@ATES 您是指 ViewPager2 中的 RecyclerView,还是在 BottomSheet 中有另一个 RecyclerView - Zain
我的意思是在ViewPager2上,向下滚动可以工作,但向上滚动不起作用,应该拖动bottomsheet而不是向上滚动。 - ATES
当我先向下滚动,然后向上滚动时,它能够正常工作,但是如果我在等待一会儿(滚动完毕时)再向上滚动,它就不起作用了 :) - ATES
最新更新:ViewPager2中的RecyclerView应该将setNestedScrollingEnabled()设置为false,但是在首次创建RecyclerView时,setNestedScrollingEnabled()应该为true,这样才能正常工作。 - ATES
显示剩余4条评论

0

如果您使用 STATE_EXPANDED 模式且 hideable 属性为 true,则无法将其向下拖动。

因此,请设置 BottomSheetBehavior.STATE_COLLAPSED 为默认模式,并设置 hideable、PeakHight 属性。

 <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="@drawable/bottom_sheet_background"
        android:orientation="vertical"
        app:layout_behavior="@string/bottom_sheet_behavior"
        
        app:behavior_peekHeight="500dp"
         app:behavior_hideable="false"

        android:clickable="true"
    android:focusable="true">

enter image description here


对我没用,TabLayout和所有区域都可拖动,除了ViewPager2,所有问题都在它上面。我已经删除了recyclerview并且它是空的,但仍然无法拖动。我找不到任何属性来解决它。 - ATES
https://dev59.com/cFIH5IYBdhLWcg3wXc5R - ATES
当我将viewpager2更改为viewpager时,它的表现很好。 - ATES

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接