Tgo1014
08/23/2021, 8:20 AMStylianos Gakis
08/23/2021, 1:21 PMTgo1014
08/23/2021, 1:26 PMStylianos Gakis
08/23/2021, 1:29 PMval goToDetailsScreen: (Long) -> Unit = { id ->
navController.navigate(Screen.DetailsScreen.createRoute(id))
}
To this:
val goToDetailsScreen: (Long) -> Unit = { id ->
if (navController.currentDestination?.route != Screen.DetailsScreen.route) {
navController.navigate(Screen.DetailsScreen.createRoute(id))
}
}
This is probably the easiest way to fix it without having to handle complex logic of if the thing should be clickable or not and confusing the user tapping it and not getting any feedback from it.
I am not sure if it’s the best way though, I’d love to hear about better options or why this may be non-optimal.Tgo1014
08/23/2021, 1:31 PMIan Lake
08/23/2021, 2:32 PMnavigate
): if (navBackStackEntry.lifecycle.currentState == Lifecycle.State.RESUMED)
Stylianos Gakis
08/23/2021, 2:42 PMif (navController.currentBackStackEntry?.lifecycle?.currentState == Lifecycle.State.RESUMED) {
navController.navigate(Screen.DetailsScreen.createRoute(id))
}
Does this mean that the state is basically not at RESUMED
while the process of navigation is happening? (While the new view is animating in for example)
But this would not prevent going to the same destination and opening it on top of itself right? (If this method was called after the navigation animation is over and we are actually on that screen)Ian Lake
08/23/2021, 3:15 PMRESUMED
, that is correct.Ian Lake
08/23/2021, 3:15 PMStylianos Gakis
08/23/2021, 3:18 PMIan Lake
08/23/2021, 3:22 PMStylianos Gakis
08/23/2021, 3:26 PMStylianos Gakis
08/31/2021, 12:32 AMI don’t know why you’d have a button navigating to yourself unless you meant to do thatActually there is this case of having destinations in a bottom navigation. In this case clicking on the item again does navigate to the same screen again. Is this expected to be handled manually at the BottomNavigation declaration like this?
onNavigation = { selectedScreen: Screen ->
if (selectedScreen != currentSelectedScreen) {
navActions.navigateToTopScreen(selectedScreen)
}
},
Stylianos Gakis
08/31/2021, 1:38 AMnavController.navigate(item.screen.route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
Which also saves the multiple backstacks which is awesome, but launchSingleTop
is what I was looking for I guessJason Ankers
11/11/2021, 2:36 AMTgo1014
11/11/2021, 8:55 AMStylianos Gakis
11/11/2021, 9:03 AMJason Ankers
11/11/2021, 9:05 AMKevin Worth
10/03/2023, 4:58 PMfun NavController.navigateSafely(safely: Boolean = true, navigate: NavController.() -> Unit) {
val state = currentBackStackEntry?.lifecycle?.currentState ?: Lifecycle.State.RESUMED
if (!safely || state == Lifecycle.State.RESUMED) {
navigate()
}
}
// Usage
navController.navigateSafely { navigate("some-route/$someVar") }
🤷Stylianos Gakis
10/03/2023, 5:05 PMlifecycle
so you can easily make something like this https://github.com/HedvigInsurance/android/blob/3b331fb73762e6b157dc211c271f397733[…]/main/kotlin/com/hedvig/android/app/navigation/HedvigNavHost.ktStylianos Gakis
10/03/2023, 5:06 PMKevin Worth
10/03/2023, 5:10 PMnavigate
methods (there are about a dozen or so).Ian Lake
10/03/2023, 5:13 PMStylianos Gakis
10/03/2023, 5:18 PMNavController.OnDestinationChangedListener
anyway, like here. But I definitely understand how if someone is doing more analytics events it’d be a problem.
Would it not be quite tricky to make that as a wrapper to the entire click listener? Suddenly your onClick modifier would need to know about the NavBackStackEntry, or at least about the lifecycle of it, even if it’s in a deep composable.
I might be lacking some imagination here, but it does feel tricky.Ian Lake
10/03/2023, 5:21 PMLocalLifecycleOwner.current
is available at every level and is already set to the NavBackStackEntryIan Lake
10/03/2023, 5:23 PMStylianos Gakis
10/03/2023, 5:40 PMLocalLifecycleOwner.current
would correctly point at the right NavBackStackEntry since Navigation sets all that up for us right?
Yeah so in some place like this, where you got access to the lifecycle and you just received your lambda to navigate, you can I suppose check for lifecycle and navigate + then do the event whatever that would be.
The screen itself still just sees a lambda that it’s triggering, so no special logic there. As long as you hoist the analytics event up there too.Kevin Worth
10/03/2023, 5:42 PMSomeItemList(
...
onClickItem: safelyClick<Item>(backStackEntry = currentEntry) {
navController.navigate("some-route/${it.someProperty}")
}
)
// Need to fill in "..."
fun <T : Any> safelyClick(safely: Boolean = true, backStackEntry: NavBackStackEntry?, onClick: (foo: T) -> Unit): (foo: T) -> Unit { ... }
…but if we’re going to have to go through all that trouble, then we might as well go with what’s been suggested:
SomeItemList(
...
onClickItem: {
if (navBackStackEntry.lifecycle.currentState == Lifecycle.State.RESUMED) {
// do any number of things (maybe stuff like analytics, etc.)
navController.navigate("some-route/${it.someProperty}")
}
}
)
😎Stylianos Gakis
10/03/2023, 5:45 PM(SomeProperty) -> Unit
, and you can handle all that at the level where your composable screen is setup, no?Kevin Worth
10/03/2023, 5:47 PMNavHost(navController = navController, startDestination = "some-destination") {
composable("some-destination") {
SomeItemList(
...
)
}
...
}
Ian Lake
10/03/2023, 5:50 PM