Skip to content

Instantly share code, notes, and snippets.

@Frank1234
Last active August 28, 2022 15:58
Show Gist options
  • Save Frank1234/9981697e8c3520807883e2530e5ab894 to your computer and use it in GitHub Desktop.
Save Frank1234/9981697e8c3520807883e2530e5ab894 to your computer and use it in GitHub Desktop.
/**
* Navigates only if this is safely possible; when this Fragment is still the current destination.
*/
fun Fragment.navigateSafe(
@IdRes resId: Int,
args: Bundle? = null,
navOptions: NavOptions? = null,
navigatorExtras: Navigator.Extras? = null
) {
if (mayNavigate()) findNavController().navigate(
resId, args,
navOptions, navigatorExtras
)
}
/**
* Navigates only if this is safely possible; when this Fragment is still the current destination.
*/
fun Fragment.navigateSafe(
deepLink: Uri,
navOptions: NavOptions? = null,
navigatorExtras: Navigator.Extras? = null
) {
if (mayNavigate()) findNavController().navigate(deepLink, navOptions, navigatorExtras)
}
/**
* Navigates only if this is safely possible; when this Fragment is still the current destination.
*/
fun Fragment.navigateSafe(directions: NavDirections, navOptions: NavOptions? = null) {
if (mayNavigate()) findNavController().navigate(directions, navOptions)
}
/**
* Navigates only if this is safely possible; when this Fragment is still the current destination.
*/
fun Fragment.navigateSafe(
directions: NavDirections,
navigatorExtras: Navigator.Extras
) {
if (mayNavigate()) findNavController().navigate(directions, navigatorExtras)
}
/**
* Returns true if the navigation controller is still pointing at 'this' fragment, or false if it already navigated away.
*/
fun Fragment.mayNavigate(): Boolean {
val navController = findNavController()
val destinationIdInNavController = navController.currentDestination?.id
// add tag_navigation_destination_id to your ids.xml so that it's unique:
val destinationIdOfThisFragment = view?.getTag(R.id.tag_navigation_destination_id) ?: destinationIdInNavController
// check that the navigation graph is still in 'this' fragment, if not then the app already navigated:
if (destinationIdInNavController == destinationIdOfThisFragment) {
view?.setTag(R.id.tag_navigation_destination_id, destinationIdOfThisFragment)
return true
} else {
Log.d("FragmentExtensions", "May not navigate: current destination is not the current fragment.")
return false
}
}
@bitvale
Copy link

bitvale commented Jul 28, 2021

This solution not working in this case: open a dialog fragment (for example BottomSheetFragment) from some HomeFragment and call navigateSafe(BottomSheetFragmentDirections.openSomeScreen()) from it. In this case navHostFragment?.childFragmentManager?.fragments?.get(0) returns HomeFragment and destinationIdInNavController is a HomeFragment id and destinationIdOfThisFragment is a dialog fragment id, destinationIdInNavController != destinationIdOfThisFragment and this action not working.

@Frank1234
Copy link
Author

That can be true, I have never needed this use case.

What would you expect, the screen in the background to navigate and the dialog/bottom sheet to stay in place? Is that what happens when you call the regular "navigate" function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment