如何启用在 BottomSheetDialogFragment 中的 ViewPager2 上拖动?
How to enable dragging on ViewPager2 inside BottomSheetDialogFragment?
在片段布局和打开 STATE_EXPANDED
模式上有一个 BottomSheetDialogFragment
并且工作良好的垂直拖动状态。它里面有一个 recyclerview
,垂直拖动在底部 sheet 上有效,但由于滚动事件,它在 recyclerview
上不起作用。当到达列表顶部并仍在向上滚动以折叠底部时,底部 sheet 拖动事件而不是 recyclerview
上的滚动事件如何工作 sheet?
BottomSheetDialogFragment 层次结构:
FragmentRootLinearLayout -> ...BottomLinearLayout... -> ViewPager2 -> RecyclerView
BottomSheetDialogFragment 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 drag to hide not works
如果使用STATE_EXPANDED模式为默认模式且可隐藏属性为真,则无法向下拖动。
因此设置 BottomSheetBehavior.STATE_COLLAPSED 为默认模式并设置可隐藏,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">
问题是我们需要禁用 ViewPager2
上的嵌套滚动,但是 android:nestedScrollingEnabled="false"
不起作用,因为 ViewPager2
在内部使用 RecyclerView
具有嵌套滚动的效果。
因此,您需要禁用 ViewPager
RecyclerView
的嵌套滚动。
主要问题是 ViewPager2
的 RecyclerView
默认情况下无法访问。
Update Feb.2022
Adding a better way to access the RecyclerView
of the ViewPager2
instead of using reflections:
科特林:
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
预览:
有思考
----
您可以使用 java reflection 访问它。
这需要知道 RecyclerView
的名称字段,可以在 ViewPager2
定义 class 中找到,即 mRecyclerView
将它们组合在辅助函数中:
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;
}
然后您可以禁用嵌套滚动,如下所示:
RecyclerView recyclerView = getRecyclerView(viewPager);
if (recyclerView != null)
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
对于 Kotlin 用户:
扩展函数:
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
}
和用法:
val recyclerView = viewPager.getRecyclerView()
recyclerView?.isNestedScrollingEnabled = false
recyclerView?.overScrollMode = View.OVER_SCROLL_NEVER // Optional
在片段布局和打开 STATE_EXPANDED
模式上有一个 BottomSheetDialogFragment
并且工作良好的垂直拖动状态。它里面有一个 recyclerview
,垂直拖动在底部 sheet 上有效,但由于滚动事件,它在 recyclerview
上不起作用。当到达列表顶部并仍在向上滚动以折叠底部时,底部 sheet 拖动事件而不是 recyclerview
上的滚动事件如何工作 sheet?
BottomSheetDialogFragment 层次结构:
FragmentRootLinearLayout -> ...BottomLinearLayout... -> ViewPager2 -> RecyclerView
BottomSheetDialogFragment 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 drag to hide not works
如果使用STATE_EXPANDED模式为默认模式且可隐藏属性为真,则无法向下拖动。
因此设置 BottomSheetBehavior.STATE_COLLAPSED 为默认模式并设置可隐藏,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">
问题是我们需要禁用 ViewPager2
上的嵌套滚动,但是 android:nestedScrollingEnabled="false"
不起作用,因为 ViewPager2
在内部使用 RecyclerView
具有嵌套滚动的效果。
因此,您需要禁用 ViewPager
RecyclerView
的嵌套滚动。
主要问题是 ViewPager2
的 RecyclerView
默认情况下无法访问。
Update Feb.2022
Adding a better way to access the
RecyclerView
of theViewPager2
instead of using reflections:
科特林:
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
预览:
您可以使用 java reflection 访问它。
这需要知道 RecyclerView
的名称字段,可以在 ViewPager2
定义 class 中找到,即 mRecyclerView
将它们组合在辅助函数中:
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;
}
然后您可以禁用嵌套滚动,如下所示:
RecyclerView recyclerView = getRecyclerView(viewPager);
if (recyclerView != null)
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
对于 Kotlin 用户:
扩展函数:
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
}
和用法:
val recyclerView = viewPager.getRecyclerView()
recyclerView?.isNestedScrollingEnabled = false
recyclerView?.overScrollMode = View.OVER_SCROLL_NEVER // Optional