如何将RecyclerView的滚动事件传递给其父级BottomSheet以使其折叠?

3

基本上,我有一个特定布局的片段,它的父级是CoordinatorLayout,并且有一个带有BottomSheetBehaviour的静态片段(还有一些与问题无关的其他视图)。

<androidx.coordinatorlayout.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/main_activity_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

       Some other views....

        <fragment
            android:id="@+id/home_apps_widget"
            android:name="apps.calo.justLauncher.fragments.HomeAppsWidget"
            android:layout_width="0dp"
            android:layout_height="57dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

    <fragment
        android:id="@+id/bottom_sheet_container"
        android:name="apps.calo.justLauncher.fragments.AppDrawerFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout="@layout/app_drawer_fragament"
        app:behavior_hideable="true"
        app:behavior_peekHeight="0dp"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
        tools:layout="@layout/app_drawer_fragament" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

在静态片段中,我有以下布局:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools">

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/app_drawer_root"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/app_drawer_background">

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/app_drawer_indicator"
            android:visibility="invisible"
            android:layout_below="@id/app_search_widget"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="5dp" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/app_list_recycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:itemCount="4"
            android:clipToPadding="false"
            app:spanCount="4"
            tools:listitem="@layout/app_item"
            android:layout_above="@id/app_drawer_indicator"
            app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
            android:orientation="vertical"
            android:layout_below="@id/app_search_widget"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="5dp" />

        <apps.calo.justLauncher.view.Pager2Indicator
            android:id="@+id/app_drawer_indicator"
            android:layout_width="wrap_content"
            android:layout_height="11dp"
            android:layout_alignParentBottom="true"
            app:piv_radius="3dp"
            app:selectedColorCustom="page_indicator_selected"
            app:tabIndicatorHeight="3dp"
            app:unselectedColorCustom="page_indicator_unselected" />

    </RelativeLayout>
</layout>

通过以下设置,您只能拥有一个活动的(recyclerview或viewpager2),可以通过SharedPreferences进行更改。
我的目标是,当您将RecyclerView滚动到顶部时,如果您再次尝试将recyclerview滚动到顶部,则下一个滚动将被底部工作表接管,并且触摸将移动底部工作表的Y位置。
我希望在viewpager中也是相同的,但是这里您不必滚动到顶部,因为它不可滚动,因此基本上,如果您向下滚动,则底部工作表将接管触摸。
使用当前设置,RecyclerView和ViewPager都“吞咽”了触摸,您无法通过它们控制底部工作表。如果您触摸位于recyclerview / viewpager上方的视图上,则仍然可以通过拉低底部工作表来折叠它。
我的问题是:如何将触摸代理从recyclerview / viewpager转移到BottomSheet以控制BottomSheet的Y位置。
有趣的事情是,当我将ViewPager2更改为ViewPager时,我可以通过RecyclerView获得期望的效果,但是不能通过ViewPager获得期望的效果。
谢谢!
2个回答

1
我想到了一种方法来实现这个。我给RecyclerView和ViewPager附加了一个触摸监听器,创建了一个连接两个片段的接口(包含底部表单和底部表单片段的片段)。在RecyclerView可见的情况下,我会检查RecyclerView是否滚动到顶部。如果是,我会检查用户是否正在向下滑动触摸监听器。如果是,我将触摸转发到包含BottomSheet的Fragment,并使用BottomSheet的根视图转发触摸事件,并运行此方法:
fun forwardTouchToBottomSheet(event: MotionEvent, view: View) {
        bottomSheetBehavior.onTouchEvent(cor, view, event)
    }

在ViewPager中,触摸监听器不会在ViewPager2视图上起作用(因为视图可能会接管触摸),所以我只是将监听器放在ViewPager内部的视图上,并通过另一个接口运行前面的方法。

你能否提供更多的代码?我遇到了同样的问题! - Sunkas
我按照你的描述进行操作时,出现了以下错误:“captureChildView: parameter must be a descendant of the ViewDragHelper's tracked parent view”。不确定在你的示例中应该传递什么参数给cor。尝试发送coordinatorLayout和父底部对话框片段的coordinatorLayout,但都没有成功。 - Sunkas

0

由于我的声望不高,无法直接回答@Sunkas的后续问题,因此我将在此扩展答案。

如果我在BottomSheetDialogFragment中初始化行为如下:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreaBottted(view, savedInstanceState)
    val behaviour = BottomSheetBehavior.from(view.parent as View).apply {
        state = BottomSheetBehavior.STATE_EXPANDED
    }
}

然后调用 onTouchEvent 需要 view.parent.parent 和 view.parent,像这样:
        binding.recyclerView.apply {
        setOnTouchListener { _, event ->
            (requireView().parent.parent as? CoordinatorLayout)?.let { coordinatorLayout ->
                (requireView().parent as? View)?.let { parentView ->
                    behaviour.onTouchEvent(coordinatorLayout, parentView, event)
                }
            } ?: false
        }
    

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