Handling back button in Android Navigation Component

前端 未结 23 1263
遥遥无期
遥遥无期 2020-11-29 18:20

I\'d like to know how properly handle system back button action using Navigation Controller. In my app I have two fragments (for ex. fragment1 and fragment2) and I have an a

相关标签:
23条回答
  • 2020-11-29 19:16

    This is 2 lines of code can listen for back press, from fragments, [TESTED and WORKING]

      requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
            @Override
            public void handleOnBackPressed() {
    
                //setEnabled(false); // call this to disable listener
                //remove(); // call to remove listener
                //Toast.makeText(getContext(), "Listing for back press from this fragment", Toast.LENGTH_SHORT).show();
         }
    
    0 讨论(0)
  • 2020-11-29 19:16

    Here is my solution

    Use androidx.appcompat.app.AppCompatActivity for the activity that contains the NavHostFragment fragment.

    Define the following interface and implement it in all navigation destination fragments

    interface InterceptionInterface {
    
        fun onNavigationUp(): Boolean
        fun onBackPressed(): Boolean
    }
    

    In your activity override onSupportNavigateUp and onBackPressed:

    override fun onSupportNavigateUp(): Boolean {
            return getCurrentNavDest().onNavigationUp() || navigation_host_fragment.findNavController().navigateUp()
    }
    
    override fun onBackPressed() {
            if (!getCurrentNavDest().onBackPressed()){
                super.onBackPressed()
            }
    }
    
    private fun getCurrentNavDest(): InterceptionInterface {
            val currentFragment = navigation_host_fragment.childFragmentManager.primaryNavigationFragment as InterceptionInterface
            return currentFragment
    }
    

    This solution has the advantage, that the navigation destination fragments don't need to worry about the unregistering of their listeners as soon as they are detached.

    0 讨论(0)
  • 2020-11-29 19:18

    Here is solution that should do what you want, but i think it is a bad solution, because it is going against Android Navigation component idea(letting the android handle the navigation).

    Override "onBackPressed" inside your activity

    override fun onBackPressed() {
        when(NavHostFragment.findNavController(nav_host_fragment).currentDestination.id) {
            R.id.fragment2-> {
                val dialog=AlertDialog.Builder(this).setMessage("Hello").setPositiveButton("Ok", DialogInterface.OnClickListener { dialogInterface, i ->
                    finish()
                }).show()
            }
            else -> {
                super.onBackPressed()
            }
        }
    } 
    
    0 讨论(0)
  • 2020-11-29 19:19

    I tried Jurij Pitulja solution but I just wasn't able to find getOnBackPressedDispatcher or addOnBackPressedCallback also using Kiryl Tkach's solution wasn't able to find the current fragment, so here's mine:

    interface OnBackPressedListener {
        fun onBackPressed(): Boolean
    }
    
    override fun onBackPressed() {
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
        val currentFragment = navHostFragment?.childFragmentManager!!.fragments[0]
        if (currentFragment !is OnBackPressedListener || !(currentFragment as OnBackPressedListener).onBackPressed()) super.onBackPressed()
    

    this way you can decide in fragment whether the activity should take control of back pressed or not.

    Alternatively, you have BaseActivity for all your activities, you can implement like this

    override fun onBackPressed() {
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
        if (navHostFragment != null){
            val currentFragment = navHostFragment.childFragmentManager.fragments[0]
            if (currentFragment !is AuthContract.OnBackPressedListener ||
                    !(currentFragment as AuthContract.OnBackPressedListener).onBackPressed()) super.onBackPressed()
        } else {
            super.onBackPressed()
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:21

    you can provide your custom back navigation by using OnBackPressedDispatcher

    class MyFragment : Fragment() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        // This callback will only be called when MyFragment is at least Started.
        val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
            // Handle the back button event
    // and if you want to need navigate up
    //NavHostFragment.findNavController(this).navigateUp()
        }
    
        // The callback can be enabled or disabled here or in the lambda
    }
    }
    

    More explanations in android official guide: https://developer.android.com/guide/navigation/navigation-custom-back

    0 讨论(0)
提交回复
热议问题