13

I'm trying to handle the back button in a BottomSheetDialogFragment, which is a DialogFragment, using 'androidx.activity:activity-ktx:1.1.0-alpha01' and 'androidx.fragment:fragment-ktx:1.2.0-alpha01'.

handleOnBackPressed() is not called and the DialogFragment is dismissed. The OnBackPressedCallback is enabled when the back button is pressed.

I think the DialogFragment is intercepting the back button press, because the ComponentActivity never calls mOnBackPressedDispatcher.onBackPressed();

Is there a way to override the DialogFragment handling of back button press?

David Corsalini
  • 7,958
  • 8
  • 41
  • 66

4 Answers4

21

It's really hard to understand what Google Android Dev making. Anyway, i found a solution without using interfaces.

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

Just override the onCreateDialog and also override onBackPressed inside it.

Mücahid Kambur
  • 1,610
  • 13
  • 10
4

One more solution:

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

Explanation

Back-pressed events are passed into the dialog of the DialogFragment, therefore you should register OnBackpressedCallback for the dialog.

Disabling the callback (isEnabled = false) allows you to prevent the consumption of the next back-pressed event. Once you disabled the callback you're retriggering the back pressed-event (calling requireActivity().onBackPressed()) and it will be consumed by someone else, e.g. your navigation will pop the back stack.

After that, you should enable the callback (isEnabled = true) to receive the next back-pressed events.

Mihail Ya
  • 361
  • 3
  • 6
3

I found a solution, but I hope the library will take care of this usecase.

Create a custom 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()
    }
}

And its interface

interface BackPressBottomSheetDialogCallback {
    fun shouldInterceptBackPress(): Boolean
    fun onBackPressIntercepted()
}

Then in your 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)
}
David Corsalini
  • 7,958
  • 8
  • 41
  • 66
3

My solution for Kotlin:

Override below method in 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
        }
    }
}
Kacper Dziubek
  • 1,513
  • 1
  • 11
  • 16