Android:嵌套底部卡片的点击/拖动触摸事件问题

11
我有一个嵌套在另一个底部工作表中的底部工作表(使用 BottomSheet 布局行为的 FrameLayouts)。
我还有一些“窥视视图”(FrameLayouts),它们附加了点击监听器,以分别展开底部工作表,当它们被点击时。
因此,应用程序基本上有 3 个主要屏幕。 “主容器”,然后是第一个“底部工作表”,可以将其展开到全屏状态,然后在第一个底部工作表的底部,是第二个底部工作表,也可以展开到全屏状态。
问题:
当我将 RecyclerView 添加到嵌套的底部工作表“容器”视图中时,拖动停止对第二个窥视视图(Sheet 2 Peek)起作用。如果我删除窥视视图 ClickListener 或 RecyclerView,似乎一切正常。
期望结果:
两个底部工作表都应保持可拖动,并且应能够单击窥视视图以展开其父底部工作表。底部工作表应像通常一样响应嵌套滚动。
我尝试删除 ClickListener 并改用触摸手势,但我尝试过的任何方法都似乎没有帮助。
我正在使用设计支持库的v25.3.1版本,并且我能够在运行4.4.4股票的Galaxy S4和运行7.1.2股票的Nexus 6P上重现这个问题。(我没有其他可用设备)。
我还为任何有兴趣仔细查看的人创建了一个Github测试项目: https://github.com/timusus/bottomsheet-test 以下是演示布局的一些屏幕截图:

1 2 3

布局结构看起来像这样(为了清晰起见省略了一些代码):
<CoordinatorLayout>

    <FrameLayout
        android:id="@+id/mainContainer" 
        android:layout_height="match_parent"/>

    <FrameLayout
        android:id="@+id/sheet1" 
        android:layout_height="match_parent"
        app:layout_behavior="CustomBottomSheetBehavior"
        app:behavior_peekHeight="64dp">

        <FrameLayout
            android:id="@+id/sheet1Container"
            android:layout_height="match_parent"/>

        <CoordinatorLayout>

        <FrameLayout
            android:id="@+id/sheet2
            android:layout_height="match_parent"
            app:layout_behavior="CustomBottomSheetBehavior"
            app:behavior_peekHeight="64dp">

            <FrameLayout
                android:id="@+id/sheet2Container"
                android:layout_height="match_parent">

                <!-- Problematic RecyclerView -->
                <RecyclerView 
                android:layout_height="match_parent"/>

            </FrameLayout>

            <!-- Problematic Click Listener on this view -->
            <FrameLayout 
                android:id="@+id/sheet2PeekView"
                android:layout_height=64dp"/>

        </FrameLayout>

        </CoordinatorLayout>

        <FrameLayout
            android:id="@+id/sheet1PeekView"
            android:layout_height=64dp"/>

    </FrameLayout>
</CoordinatorLayout/>

CustomBottomSheetBehaviorBottomSheetBehavior 的一个简单子类,如果第二个底部工作表已展开或正在拖动,则会阻止第一个工作表拦截触摸事件。这使得第二个工作表可以从“展开”到“折叠”,而不会同时折叠第一个工作表。

public class CustomBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {

    private boolean allowDragging = true;

    public void setAllowDragging(boolean allowDragging) {
        this.allowDragging = allowDragging;
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        if (!allowDragging) {
            return false;
        }

        return super.onInterceptTouchEvent(parent, child, event);
    }
}

我不认为自定义BottomSheetBehavior与这个问题有关,但为了完整起见,这里介绍一下它的使用方法:

FrameLayout sheet1 = (FrameLayout) findViewById(R.id.sheet1);
bottomSheetBehavior1 = (CustomBottomSheetBehavior) BottomSheetBehavior.from(sheet1);

FrameLayout sheet2 = (FrameLayout) findViewById(R.id.sheet2);
       bottomSheetBehavior2 = (CustomBottomSheetBehavior) BottomSheetBehavior.from(sheet2);
       bottomSheetBehavior2.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
           @Override
           public void onStateChanged(@NonNull View bottomSheet, int newState) {
                //If the second sheet is expanded or dragging, don't allow the first sheet to respond to touch events.
               if (newState == BottomSheetBehavior.STATE_EXPANDED || newState == BottomSheetBehavior.STATE_DRAGGING) {
                   bottomSheetBehavior1.setAllowDragging(false);
               } else {
                   bottomSheetBehavior1.setAllowDragging(true);
               }
           }

我似乎无法确定这是否与BottomSheetonInterceptTouchEvent、内部RecyclerView的嵌套滚动处理、View.ClickListener窃取触摸事件、以上组合或其他原因有关。非常感谢您的任何帮助。

通过xml添加CustomBottomSheetBehavior导致错误。我该如何通过xml提供myCustomBottomSheetBehavior? - Gentle
1个回答

22

已修复

我似乎无法确定这是与 BottomSheet 的 onInterceptTouchEvent、内部 RecyclerView 的嵌套滚动处理、View.ClickListener 夺取触摸事件、以上组合还是其他原因有关。

这是上述CustomBottomSheetBehaviorView.ClickListener的组合问题。

问题在于bottomSheetBehavior1getSheet2PeekView拖动时会接收拖动事件,因此需要检测getSheet2PeekView上的触摸事件并将bottomSheetBehavior1的拖动设置为false,将bottomSheetBehavior2的设置为true


解决方案

将以下代码放入即可解决该问题。

findViewById(getSheet2PeekViewResId()).setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.e(TAG, "onTouch: ");
            bottomSheetBehavior1.setAllowDragging(false);
            bottomSheetBehavior2.setAllowDragging(true);
            return false;
        }
    });

我还创建了一个Pull Request,向你的存储库提交了完全可用的更改。


1
监听触摸事件是个好主意。我通过以下方式实现了我想要的行为: bottomSheetDialog.setHideable(false); - bastiotutuama

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