Reputation: 980
I am trying to add a Listener and receive a callback whenever the navigation transition has finished in Jetpack Compose.
I have tried to use the NavController API addOnDestinationChangedListener
but it is send immediately to my listener and is not waiting for the composition to finish.
val navController = rememberNavController()
// Register the destination changed listener
navController.addOnDestinationChangedListener { _, destination, _ ->
// destination change is sent immediately and isnt waiting for the composable to finish
}
My goal is to add a listener that is only fired once the composition is completed and the destination is changed.
something like this:
// Register the transition finished listener
navController.transitionFinished{ _, destination ->
// Do something when the navigation transition has finished
}
NavHost(navController = navController, startDestination = "Home") {
composable("Home") {
// THE CALLBACK IS FIRED HERE, IMMEDITIETLY
Text("FIRST SITE")
//FIRE NOW THE CALLBACK AFTER IT FINISHED COMPOSITION
}
composable("Settings") {
// THE CALLBACK IS FIRED HERE, IMMEDITIETLY
Text("SECOND SITE")
//FIRE NOW THE CALLBACK AFTER IT FINISHED COMPOSITION
}
}
Where it will only fire callback once the whole composable is finished its composition.
Are there options to get the current tranistioning state of the navHost so I can implement it myself or any other API calls I can use?
EDIT1: TO Clarify: I define finishing composition as the whole transition animation is finished
Upvotes: 12
Views: 6693
Reputation: 3258
I had a simpler idea using a launched effect:
NavHost(navController = navController, startDestination = "Home") {
composable("Home") {
ScreenHome()
}
composable("Settings") {
ScreenSettings( doOnCompositionfinished = {executeMyCallback()})
}
}
ScreenSettings( doOnCompositionfinished:()->Unit){
LaunchedEffect(key1 = true) {
doOnCompositionFinished()
}
....
}
the launched effect will for sure only get executed one time once the Settings Screen is composed
Upvotes: 0
Reputation: 1029
I had the same problem but not with the compose. I used addOnDestinationChangedListener to change the title but the title was always updated before the destination was shown. But eventually I fixed it as follows:
navController.addOnDestinationChangedListener { controller, destination, args ->
view?.post{
title = destination.lable
}
}
The view here is the rootView of your hosting view which can be an activity, fragment or dialog. Post function will make sure that the root view is fully loaded including the destination before executing the runnable passed in to it. you can use args or label in you navigation graph to pass on the name.
Upvotes: 4
Reputation: 7005
I'm a bit confused by your code because it seems you are mixing classic AndroidX Navigation (findNavController()
) and Navigation Compose here.
Here's a full Compose example of what you want to achieve:
val navController = rememberNavController()
val currentBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute by remember { derivedStateOf { currentBackStackEntry?.destination?.route ?: "Home" } }
NavHost(
navController = navController,
startDestination = "Home",
) {
...
}
The value of currentRoute
contains the current route of the NavController
and since it's a State
it automatically updates when the destination changes.
Upvotes: 9