DialogFragment 忽略 OnBackPressedDispatcher

问题描述 投票:0回答:5

我正在尝试使用

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
按下后退按钮的处理?

android android-fragments androidx
5个回答
21
投票

很难理解 Google Android Dev 所做的事情。不管怎样,我找到了一个不使用接口的解决方案。

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return object : Dialog(requireContext(), theme) {
        override fun onBackPressed() {
            // handle back press
        }
    }
}

只需重写 onCreateDialog 并重写其中的 onBackPressed 即可。


7
投票

还有一个解决方案:

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
)以接收下一个背按事件。


4
投票

我的 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
        }
    }
}

3
投票

我找到了解决方案,但我希望图书馆能够处理这个用例。

创建自定义

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)
}

0
投票

我们应该使用

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              
        }
      },
    )
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.