architecture-samples icon indicating copy to clipboard operation
architecture-samples copied to clipboard

Fragment Navigation should be after Modal Drawer Animation is finished

Open arduia opened this issue 5 years ago • 1 comments

When a menu item is selected on the opening Navigation Drawer ( Modal Drawer ), Drawer closure is started with dragging animation to the left. With this, Fragment for selected item is also instantly transacted on the Main-Thread.

That Fragment Transaction disturbs Drawer Closure Animation and gives Bad User Experience.

I want to suggest that the Fragment Navigation should be after Drawer Closure for smooth animation.

arduia avatar Jun 19 '20 05:06 arduia

You're absolutely right — triggering a fragment navigation immediately when a navigation drawer item is tapped can interrupt the drawer's closing animation, leading to a janky UI experience.

Goal Wait for the drawer closing animation to complete, and then navigate to the new fragment.

Recommended Solution Use a DrawerListener and delay navigation until the drawer is completely closed:

binding.drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener { override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}

override fun onDrawerOpened(drawerView: View) {}

override fun onDrawerClosed(drawerView: View) {
    // Navigate here
    findNavController(R.id.nav_host_fragment).navigate(R.id.yourFragment)
    binding.drawerLayout.removeDrawerListener(this) // Clean up
}

override fun onDrawerStateChanged(newState: Int) {}

}) And in your menu item click:

binding.navView.setNavigationItemSelectedListener { menuItem -> // Close drawer first binding.drawerLayout.closeDrawer(GravityCompat.START)

// Save destination ID for later use
selectedDestinationId = when (menuItem.itemId) {
    R.id.nav_home -> R.id.homeFragment
    R.id.nav_settings -> R.id.settingsFragment
    else -> null
}

true

} Then modify the onDrawerClosed() to use that selectedDestinationId.

Better Approach with NavController (Single Source of Truth) To avoid multiple listeners and leaks, you could create a wrapper method:

private fun navigateAfterDrawerClose(@IdRes destinationId: Int) { binding.drawerLayout.addDrawerListener(object : DrawerLayout.SimpleDrawerListener() { override fun onDrawerClosed(drawerView: View) { findNavController(R.id.nav_host_fragment).navigate(destinationId) binding.drawerLayout.removeDrawerListener(this) } }) binding.drawerLayout.closeDrawer(GravityCompat.START) } Then call it cleanly:

binding.navView.setNavigationItemSelectedListener { navigateAfterDrawerClose(R.id.settingsFragment) true } Result This ensures the drawer closes fully with a smooth animation and only then performs the fragment transaction — giving your users a seamless experience.

VaradGupta23 avatar Jul 21 '25 06:07 VaradGupta23