我有一个带有RecyclerView
的BottomSheetDialogFragment
。问题是,只要RecyclerView
没有向上滚动,我想禁用BottomSheetDialogFragment
的拖动关闭功能(当前我无法滚动RecyclerView
,因为尝试滚动将始终关闭BottomSheetDialogFragment
)。有什么办法可以实现这一点吗?
我有一个带有RecyclerView
的BottomSheetDialogFragment
。问题是,只要RecyclerView
没有向上滚动,我想禁用BottomSheetDialogFragment
的拖动关闭功能(当前我无法滚动RecyclerView
,因为尝试滚动将始终关闭BottomSheetDialogFragment
)。有什么办法可以实现这一点吗?
通过这种方式可以解决BottomSheetDialog中RecyclerView滚动问题。
来自:https://android.jlelse.eu/recyclerview-within-nestedscrollview-scrolling-issue-3180b5ad2542
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
在扩展 RecyclerView
的 Fragment
中,在 onCreateView
方法中尝试此操作。
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);
v.onTouchEvent(event);
return true;
}
});
只需在您的布局中添加一个属性:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/receiversList"
android:nestedScrollingEnabled="false"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
android:nestedScrollingEnabled="false"
可以完成所有工作。
此外,如果你用 SwipeRefreshLayout
包裹你的 RecyclerView
- 刷新功能仍将继续工作。并且即使你使用更复杂的视图布局,你的 BottomSheetDialog
也将继续支持向下拖动关闭行为(如果滑动手势发生在 RecyclerView
& SwipeRefreshLayout
外部)。
只需将它视为一个 BottomSheetDialog,并在触摸时禁用其拖动或滑动。
创建 BottomSheetDialog 时,它会自动将您的布局包装在CoordinatorLayout 中,因此如果您想从您的视图中获取行为,则调用
final BottomSheetBehavior behavior = BottomSheetBehavior.from((View) view.getParent());
然后通过这个行为,你可以做你需要的事情。
final BottomSheetBehavior behavior = BottomSheetBehavior.from((View) view.getParent());
behavior.setHideable(false);
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
});
这对我很有帮助,希望能对你有所帮助。
behavior.setHideable(false);
helped for me, it prevents scrolling the bottom sheet. However, when the user taps the back button, I call behavior.setHideable(true);
so that I can then call behavior.setState(BottomSheetBehavior.STATE_HIDDEN);
- Michael OsofskyNestedScrollView
时,一个BottomSheetDialog
会反弹。我只是删除了BottomSheetBehavior
和android:minHeight
,然后NSV就可以在BottomSheetDialog
的整个高度上滚动了。 - CoolMind <androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/layout_form"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<!-- elements-->
<!-- elements-->
</LinearLayout>
</androidx.core.widget.NestedScrollView>
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
behavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
dismiss();
}
if (newState == BottomSheetBehavior.STATE_DRAGGING) {
if(!recyclerView.canScrollVertically(1)) {
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
更改setupDialog方法中BottomSheetDialogFragment的行为:
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams();
final CoordinatorLayout.Behavior behavior = layoutParams.getBehavior();
if (behavior != null && behavior instanceof BottomSheetBehavior) {
((BottomSheetBehavior) behavior).setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
dismiss();
}
if (newState == BottomSheetBehavior.STATE_DRAGGING) {
((BottomSheetBehavior) behavior).setState(BottomSheetBehavior.STATE_EXPANDED);
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
}
RecyclerView
是否滚动到顶部,然后这应该可以工作。 - prom85可以使用以下方法在BottomSheet中滚动RecyclerView:
在XML文件中的RecyclerView中添加android:focusableInTouchMode="true"。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
android:clipToPadding="false"
android:focusableInTouchMode="true"
android:paddingBottom="50dp" />
- 对于 BottomSheet,func onCreateDialog 中: + maxDesiredHeight 参数代表 BottomSheet 的固定高度。 + this.isDraggable = false -> 禁用 BottomSheet 的拖拽功能。
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
dialog.setOnShowListener {
dialog.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)!!
.apply {
val maxDesiredHeight = (resources.displayMetrics.heightPixels * 0.95).toInt()
val bottomSheetLayoutParams = this.layoutParams
bottomSheetLayoutParams.height = maxDesiredHeight
this.layoutParams = bottomSheetLayoutParams
BottomSheetBehavior.from(this).apply {
this.state = BottomSheetBehavior.STATE_EXPANDED
this.isDraggable = false
}
}
}
return dialog
}
- 为 RecyclerView 调用 setOnTouchListener 函数:
Recycler.setOnTouchListener { v, event ->
v.parent.requestDisallowInterceptTouchEvent(true)
v.onTouchEvent(event)
true
}
最近在我的项目中遇到了同样的问题,我尝试了这个和其他SO线程中提出的所有答案,但都没有成功,所以我决定用自己的方法解决它。
只是一个注意事项,我的情况是我有一个具有复杂布局的BottomSheetDialog,结果类似于这样
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="_mainLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id=" />
<LinearLayout
android:id="">
<ImageView
android:id=""/>
<LinearLayout
android:id="">
<TextView
android:id="" />
<TextView
android:id=""/>
</LinearLayout>
<LinearLayout
android:id="">
<TextView
android:id=""/>
</LinearLayout>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:layout_marginTop="10dp"
android:id=""
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:id="">
<Button
android:id="">
</LinearLayout>
_bottomSheetBehavior = BottomSheetBehavior.From((View)_mainLayout.Parent);
_bottomSheetCallback = new BottomSheetFullScreenCallback(_bottomSheetBehavior);
_bottomSheetBehavior.AddBottomSheetCallback(_bottomSheetCallback);
_recyclerView.SetOnTouchListener(new MyTouchListener(_bottomSheetBehavior));
public bool OnTouch(View view, MotionEvent e)
{
if (e.Action == MotionEventActions.Down || e.Action == MotionEventActions.Move)
{
_bottomSheetBehavior.Draggable = false;
}
if (e.Action == MotionEventActions.Up)
{
_bottomSheetBehavior.Draggable = true;
}
return true;
}
完成这一步骤后,我们需要确保自定义BottomSheetCallback的OnSlide事件在bottomSheetBehavior不可拖动时不会被调用,我们可以通过以下方式实现:
public override void OnSlide(View bottomSheet, float slideOffset)
{
if (_bottomSheetBehavior.Draggable)
{
OnSlideEvent?.Invoke(this, slideOffset);
}
}
就是这样了 ;)
我遇到了同样的情况,对我起作用的是在onCreate
函数中只有一行代码。
你需要做的就是启用RecyclerView的嵌套滚动。
recyclerView.setNestedScrollingEnabled(true);
RecyclerView
已经支持作为一个嵌套滚动视图了... - prom85