我正在尝试使用
BottomSheetDialogFragment
和 DialogFragment
来处理 'androidx.activity:activity-ktx:1.1.0-alpha01'
中的后退按钮,这是一个 'androidx.fragment:fragment-ktx:1.2.0-alpha01'
。
handleOnBackPressed()
未被调用并且 DialogFragment
被忽略。按下后退按钮时会启用 OnBackPressedCallback
。
我认为
DialogFragment
正在拦截后退按钮按下,因为 ComponentActivity
永远不会调用 mOnBackPressedDispatcher.onBackPressed();
有没有办法覆盖
DialogFragment
按下后退按钮的处理?
很难理解 Google Android Dev 所做的事情。不管怎样,我找到了一个不使用接口的解决方案。
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return object : Dialog(requireContext(), theme) {
override fun onBackPressed() {
// handle back press
}
}
}
只需重写 onCreateDialog 并重写其中的 onBackPressed 即可。
还有一个解决方案:
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).also {
val componentDialog = it as ComponentDialog
componentDialog.onBackPressedDispatcher.addCallback(this) {
val backPressedConsumed = yourLegacyLogic()
if (backPressedConsumed.not()) {
isEnabled = false
requireActivity().onBackPressedDispatcher.onBackPressed()
isEnabled = true
}
}
}
}
后按事件会传递到
dialog
的 DialogFragment
,因此您应该为 OnBackpressedCallback
注册 dialog
。
禁用回调(
isEnabled = false
)可以防止消耗下一个背按事件。
一旦您禁用回调,您将重新触发后按事件(调用 requireActivity().onBackPressed()
),并且它将被其他人消耗,例如您的导航将弹出后退堆栈。
之后,您应该启用回调(
isEnabled = true
)以接收下一个背按事件。
我的 Kotlin 解决方案:
在
BottomSheetDialogFragment
中重写以下方法。
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
setOnKeyListener { _: DialogInterface, keyCode: Int, keyEvent: KeyEvent ->
if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
// your code
// return true if you want keep dialog visible
// return false if you want to dismiss dialog anyway
return@setOnKeyListener true
}
return@setOnKeyListener false
}
}
}
我找到了解决方案,但我希望图书馆能够处理这个用例。
创建自定义
BottomSheetDialog
:
class BackPressBottomSheetDialog(context: Context, @StyleRes theme: Int,
private val callback: BackPressBottomSheetDialogCallback) :
BottomSheetDialog(context, theme) {
override fun onBackPressed() {
if (callback.shouldInterceptBackPress()) callback.onBackPressIntercepted()
else super.onBackPressed()
}
}
还有它的
interface
interface BackPressBottomSheetDialogCallback {
fun shouldInterceptBackPress(): Boolean
fun onBackPressIntercepted()
}
然后在你的
BottomSheetDialogFragment
private val dialogCallback = object : BackPressBottomSheetDialogCallback {
override fun shouldInterceptBackPress(): Boolean {
//TODO should you intercept the back button?
}
override fun onBackPressIntercepted() {
//TODO what happens when you intercept the back button press
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return BackPressBottomSheetDialog(requireContext(), theme, dialogCallback)
}
AppCompatDialog
来代替。它有一个OnBackPressDispatcher
:
// DialogFragment
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return AppCompatDialog(requireContext(), theme).apply {
onBackPressedDispatcher.addCallback(
owner = this,
onBackPressedCallback = object : OnBackPressedCallback(enabled = true) {
override fun handleOnBackPressed() {
// do some back stuff when back press happens
}
},
)
}
}
AppCompatDialogFragment
这样做是为了你,但你一定很沮丧,所以我不确定这样更好。
// AppCompatDialogFragment
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return (super.onCreateDialog(/* savedInstanceState = */ savedInstanceState) as ComponentDialog).apply {
onBackPressedDispatcher.addCallback(
owner = this,
onBackPressedCallback = object : OnBackPressedCallback(enabled = true) {
override fun handleOnBackPressed() {
// do some back stuff when back press happens
}
},
)
}
}