Android: 嵌套底部 sheet click/drag 触摸事件问题

Android: Nested bottom sheet click/drag touch event issue

我有一个底部 sheet 嵌套在另一个底部 sheet 中(FrameLayouts 使用 BottomSheet 布局行为)

我还有几个 'peek views' (FrameLayouts),它们附加了点击侦听器,在点击时分别展开底部 sheet(s)。

所以应用程序基本上有 3 个主屏幕。 'main container',然后是第一个'bottom sheet',可以展开全屏,然后是第一个底部sheet,第二个底部sheet,也就是也可以展开全屏。

问题:

当我将 RecyclerView 添加到嵌套的底部 sheet 'container' 视图时,拖动对第二个速览视图(Sheet 2 Peek)停止工作。如果我删除 peek 视图 ClickListener RecyclerView,事情似乎工作得很好。

想要的结果:

两个底部 sheet 都应保持可拖动状态,并且应该可以单击速览视图以展开其父底部 sheet。底部 sheet 应该像往常一样响应嵌套卷轴。

我试过删除 ClickListener 并改用触摸手势,但我尝试过的似乎都无济于事。

我正在使用设计支持库的 v25.3.1,我能够在 Galaxy S4 运行 4.4.4 库存和 Nexus 6P [=91] 上重现此问题=] 7.1.2 股票。 (我没有任何其他可用的设备)。

我还在 github 上创建了一个测试项目,供有兴趣仔细查看的任何人使用: https://github.com/timusus/bottomsheet-test

下面是展示布局的几个屏幕截图:

布局结构如下所示(为清楚起见省略了一些代码):

<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/>

CustomBottomSheetBehavior 只是 BottomSheetBehavior 的一个简单子类,如果第二个 sheet 展开或拖动,它会阻止第一个 sheet 拦截触摸事件。这允许将第二个 sheet 从 'expanded' 拖到 'collapsed' 而不会折叠第一个 sheet.

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、内部 RecyclerViewView.ClickListener 的嵌套滚动处理有关窃取触摸事件,上述的组合,或者其他的东西。

如有任何帮助,我们将不胜感激。

固定

I can't seem to figure out if this is to do with the onInterceptTouchEvent of the BottomSheet, nested scroll handling of the inner RecyclerView, View.ClickListener stealing touch events, a combination of the above, or something else altogether.

是上面CustomBottomSheetBehaviorView.ClickListener

的组合

问题是 bottomSheetBehavior1getSheet2PeekView 拖动时发生拖动事件,因此在 getSheet2PeekView[=37 上检测触摸事件=] 并设置 bottomSheetBehavior1 拖动 falsebottomSheetBehavior2 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,并进行了完全有效的更改。