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);
}
}
我似乎无法弄清楚这是否与 BottomSheet
的 onInterceptTouchEvent
、内部 RecyclerView
、View.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.
是上面CustomBottomSheetBehavior和View.ClickListener
的组合
问题是 bottomSheetBehavior1 在 getSheet2PeekView 拖动时发生拖动事件,因此在 getSheet2PeekView[=37 上检测触摸事件=] 并设置 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,并进行了完全有效的更改。
我有一个底部 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);
}
}
我似乎无法弄清楚这是否与 BottomSheet
的 onInterceptTouchEvent
、内部 RecyclerView
、View.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.
是上面CustomBottomSheetBehavior和View.ClickListener
的组合问题是 bottomSheetBehavior1 在 getSheet2PeekView 拖动时发生拖动事件,因此在 getSheet2PeekView[=37 上检测触摸事件=] 并设置 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,并进行了完全有效的更改。