I have an app, which represent a screen with bottom bar with 4 tabs. I use compose navigation with bottom bar. When user clicks on the bar the screen appears. How can I handle the situation when user clicks on the bar button for the 2-nd time, I need to listen to this event from the current inner screen and scroll the content up or do something else.
I investigate that I should use currentBackStackEntryAsState
, but I am not sure which way.
You can build classes shared in your compose tree with staticCompositionLocalOf
.
For this purpose I've build CurrentTabClickHandler
- it's API is similar to BackHandler
:
@Composable
fun CurrentTabClickHandler(
enabled: Boolean = true,
onTabClick: suspend () -> Unit,
) {
val currentOnTabClick by rememberUpdatedState(onTabClick)
val currentEnabled by rememberUpdatedState(enabled)
val coroutineScope = rememberCoroutineScope()
val handler = remember {
CurrentTabClickDispatcher.Handler {
if (currentEnabled) {
coroutineScope.launch {
currentOnTabClick()
}
}
}
}
val currentTabClickDispatcher = LocalCurrentTabClickDispatcher.current
DisposableEffect(Unit) {
currentTabClickDispatcher.addHandler(handler)
onDispose {
currentTabClickDispatcher.removeHandler(handler)
}
}
}
class CurrentTabClickDispatcher {
class Handler(val action: () -> Unit)
private val handlers = mutableListOf<Handler>()
fun addHandler(handler: Handler) {
handlers.add(handler)
}
fun removeHandler(handler: Handler) {
handlers.remove(handler)
}
fun currentHandler() =
handlers.lastOrNull()
}
val LocalCurrentTabClickDispatcher = staticCompositionLocalOf {
CurrentTabClickDispatcher()
}
So in the screen you use it like this:
CurrentTabClickHandler {
// to your action
}
And to perform this action add this code to BottomNavigationItem
:
val currentTabClickDispatcher = LocalCurrentTabClickDispatcher.current
BottomNavigationItem(
// ...
selected = isCurrent,
onClick = {
if (isCurrent) {
when (val handler = currentTabClickDispatcher.currentHandler()) {
null -> {
// no action is specified - I pop to initial tab screen here
}
else -> handler.action()
}
} else {
// change tab
}
},