如何允许 BottomSheetDialog 的外部触摸?
How to Allow outside touch for BottomSheetDialog?
我正在研究 BottomSheetDialogFragment
我的要求是创建底部菜单,
如果我单击外部片段区域,它应该不会取消 对话框并且应该保留。
问题:
片段外的事件应该传播到较低的片段view/fragment。
我已经在下面尝试过(不适用于 BottomDialogFragment):
Allow outside touch for DialogFragment
为了停止对话框取消,我在下面尝试了(我在 BottomDialogFragment 的 onStart()
中调用了 setCancelable(boolean)
):
@Override
public void setCancelable(boolean cancelable) {
super.setCancelable(cancelable);
BottomSheetDialog dialog = (BottomSheetDialog) getDialog();
dialog.setCanceledOnTouchOutside(cancelable);
View bottomSheetView = dialog.getWindow().getDecorView().findViewById(R.id.design_bottom_sheet);
BottomSheetBehavior.from(bottomSheetView).setHideable(cancelable);
}
编辑:很难发现没有其他方法然后使用坐标 layout.The BottomSheetDialog 的最佳解决方案是 here
在您的BottomSheetDialog
中尝试下面的代码:
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return (super.onCreateDialog(savedInstanceState) as BottomSheetDialog).apply {
setCanceledOnTouchOutside(false)
}
}
或用 <CoordinatorLayout>
包装,例如您的 <ConstraintLayout>
并实施 <layout />
并附加到 BottomSheetBehavior
。
在您使用 BottomSheetDialogFragment
之前,这是不可能的。 BottomSheetDialogFragment
是一个对话框,作为每个对话框的行为,它不允许用户在对话框后面的任何视图上进行拦截,尽管这对用户可见。
因此,要实现这一点,您需要使用 Fragment
而不是 BottomSheetDialogFragment
。是的,它需要大量的代码更改 :) 如果你想拦截后面的视图,你必须没有 BottomSheetDialogFragment
生活。
你应该使用 android.support.design.widget.BottomSheetBehavior
.
但如果您想在其他 class 中使用 bottomSheet
,我建议您使用 Fragment
并在此 fragment
中打开您的 bottomSheet
打开你的片段。
然后在您的片段中,用以下代码打开您的 bottomSheet
:
在onInitViews
var mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheetCoordinatorLayout)
mBottomSheetBehavior!!.state = BottomSheetBehavior.STATE_HIDDEN
mBottomSheetBehavior!!.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_HIDDEN -> {
fragmentManager?.popBackStack()
}
//BottomSheetBehavior.STATE_COLLAPSED -> "Collapsed"
//BottomSheetBehavior.STATE_DRAGGING -> "Dragging..."
//BottomSheetBehavior.STATE_EXPANDED -> "Expanded"
//BottomSheetBehavior.STATE_SETTLING -> "Settling..."
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
//text_view_state!!.text = "Sliding..."
}
})
而你的layout
应该是这样的:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutDirection="ltr">
<android.support.design.widget.CoordinatorLayout
android:id="@+id/bottomSheetCoordinatorLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:behavior_hideable="true"
app:behavior_peekHeight="55dp"
app:layout_behavior="@string/bottom_sheet_behavior">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/top_radius_primary_color"
android:paddingStart="@dimen/material_size_32"
android:paddingEnd="@dimen/material_size_32">
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
</android.support.design.widget.CoordinatorLayout>
希望对你有帮助
正如 Pankaj Kumar 所说,默认情况下这是不可能的。但是,我找到了一种可行的解决方法,它允许触摸底部 sheet 之外的视图,同时保持底部 sheet 打开
您可以像这样覆盖 BottomSheetDialog
的布局:
values/refs.xml
<resources xmlns:tools="http://schemas.android.com/tools">
<item name="design_bottom_sheet_dialog" type="layout" tools:override="true">@layout/custom_design_bottom_sheet_dialog</item>
</resources>
layout/custom_design_bottom_sheet_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
~ This is an override of the design_bottom_sheet_dialog from material library
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="@+id/touch_outside"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
android:importantForAccessibility="no"
android:soundEffectsEnabled="false"
tools:ignore="UnusedAttribute"/>
<FrameLayout
android:id="@+id/design_bottom_sheet"
style="?attr/bottomSheetStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
app:layout_behavior="@string/bottom_sheet_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</FrameLayout>
你的CustomBottomSheetDialogFragment
override fun onStart() {
super.onStart()
// Set layout for custom bottom sheet by allowing background touches
dialog?.window?.apply {
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)
attributes = attributes.apply {
gravity = Gravity.BOTTOM
}
setDimAmount(0.0f)
}
}
通过这样做,对话框有一个 wrap_content
高度并且标志允许触摸被这个对话框之外的视图处理
我正在研究 BottomSheetDialogFragment
我的要求是创建底部菜单,
如果我单击外部片段区域,它应该不会取消 对话框并且应该保留。
问题: 片段外的事件应该传播到较低的片段view/fragment。
我已经在下面尝试过(不适用于 BottomDialogFragment): Allow outside touch for DialogFragment
为了停止对话框取消,我在下面尝试了(我在 BottomDialogFragment 的 onStart()
中调用了 setCancelable(boolean)
):
@Override
public void setCancelable(boolean cancelable) {
super.setCancelable(cancelable);
BottomSheetDialog dialog = (BottomSheetDialog) getDialog();
dialog.setCanceledOnTouchOutside(cancelable);
View bottomSheetView = dialog.getWindow().getDecorView().findViewById(R.id.design_bottom_sheet);
BottomSheetBehavior.from(bottomSheetView).setHideable(cancelable);
}
编辑:很难发现没有其他方法然后使用坐标 layout.The BottomSheetDialog 的最佳解决方案是 here
在您的BottomSheetDialog
中尝试下面的代码:
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return (super.onCreateDialog(savedInstanceState) as BottomSheetDialog).apply {
setCanceledOnTouchOutside(false)
}
}
或用 <CoordinatorLayout>
包装,例如您的 <ConstraintLayout>
并实施 <layout />
并附加到 BottomSheetBehavior
。
在您使用 BottomSheetDialogFragment
之前,这是不可能的。 BottomSheetDialogFragment
是一个对话框,作为每个对话框的行为,它不允许用户在对话框后面的任何视图上进行拦截,尽管这对用户可见。
因此,要实现这一点,您需要使用 Fragment
而不是 BottomSheetDialogFragment
。是的,它需要大量的代码更改 :) 如果你想拦截后面的视图,你必须没有 BottomSheetDialogFragment
生活。
你应该使用 android.support.design.widget.BottomSheetBehavior
.
但如果您想在其他 class 中使用 bottomSheet
,我建议您使用 Fragment
并在此 fragment
中打开您的 bottomSheet
打开你的片段
然后在您的片段中,用以下代码打开您的 bottomSheet
:
在onInitViews
var mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheetCoordinatorLayout)
mBottomSheetBehavior!!.state = BottomSheetBehavior.STATE_HIDDEN
mBottomSheetBehavior!!.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_HIDDEN -> {
fragmentManager?.popBackStack()
}
//BottomSheetBehavior.STATE_COLLAPSED -> "Collapsed"
//BottomSheetBehavior.STATE_DRAGGING -> "Dragging..."
//BottomSheetBehavior.STATE_EXPANDED -> "Expanded"
//BottomSheetBehavior.STATE_SETTLING -> "Settling..."
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
//text_view_state!!.text = "Sliding..."
}
})
而你的layout
应该是这样的:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutDirection="ltr">
<android.support.design.widget.CoordinatorLayout
android:id="@+id/bottomSheetCoordinatorLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:behavior_hideable="true"
app:behavior_peekHeight="55dp"
app:layout_behavior="@string/bottom_sheet_behavior">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/top_radius_primary_color"
android:paddingStart="@dimen/material_size_32"
android:paddingEnd="@dimen/material_size_32">
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
</android.support.design.widget.CoordinatorLayout>
希望对你有帮助
正如 Pankaj Kumar 所说,默认情况下这是不可能的。但是,我找到了一种可行的解决方法,它允许触摸底部 sheet 之外的视图,同时保持底部 sheet 打开
您可以像这样覆盖 BottomSheetDialog
的布局:
values/refs.xml
<resources xmlns:tools="http://schemas.android.com/tools">
<item name="design_bottom_sheet_dialog" type="layout" tools:override="true">@layout/custom_design_bottom_sheet_dialog</item>
</resources>
layout/custom_design_bottom_sheet_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
~ This is an override of the design_bottom_sheet_dialog from material library
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="@+id/touch_outside"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
android:importantForAccessibility="no"
android:soundEffectsEnabled="false"
tools:ignore="UnusedAttribute"/>
<FrameLayout
android:id="@+id/design_bottom_sheet"
style="?attr/bottomSheetStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
app:layout_behavior="@string/bottom_sheet_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</FrameLayout>
你的CustomBottomSheetDialogFragment
override fun onStart() {
super.onStart()
// Set layout for custom bottom sheet by allowing background touches
dialog?.window?.apply {
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)
attributes = attributes.apply {
gravity = Gravity.BOTTOM
}
setDimAmount(0.0f)
}
}
通过这样做,对话框有一个 wrap_content
高度并且标志允许触摸被这个对话框之外的视图处理