New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Accessing Tab's navigator through TabNavigator #83
Comments
If you call |
TabNavigator is a very small module you can build your own easily :) Here's a version that allows what you want. (You probably have to tweak things as it's for my needs) import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.SaveableStateHolder
import androidx.compose.runtime.staticCompositionLocalOf
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.NavigatorDisposeBehavior
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
typealias TabNavigatorContent = @Composable (tabNavigator: TabNavigator) -> Unit
val LocalTabNavigator: ProvidableCompositionLocal<TabNavigator> =
staticCompositionLocalOf { error("TabNavigator not initialized") }
@Composable
fun TabNavigator(
tab: Tab,
backToFirst: Boolean = false,
content: TabNavigatorContent = { CurrentTab() }
) {
Navigator(tab, disposeBehavior = NavigatorDisposeBehavior(disposeNestedNavigators = false, disposeSteps = false), onBackPressed = null) { navigator ->
val scope = rememberCoroutineScope()
val tabNavigator = remember(navigator) {
TabNavigator(navigator, scope)
}
CompositionLocalProvider(LocalTabNavigator provides tabNavigator) {
if (backToFirst) {
BackHandler(
enabled = tabNavigator.current != tab,
onBack = { tabNavigator.current = tab }
)
}
content(tabNavigator)
}
}
}
private val tabReselectHandlers = mutableListOf<suspend () -> Boolean>()
class TabNavigator internal constructor(
private val navigator: Navigator,
private val coroutineScope: CoroutineScope,
val stateHolder: SaveableStateHolder = navigator.stateHolder
) {
var current: Tab
get() = navigator.lastItem as Tab
set(tab) {
if (navigator.lastItem == tab) {
coroutineScope.launch {
tabReselectHandlers.reversed().firstOrNull { it.invoke() }
}
} else {
navigator.replaceAll(tab)
}
}
}
@Composable
fun TabReselectHandler(handler: suspend () -> Boolean) {
DisposableEffect(Unit) {
tabReselectHandlers.add(handler)
onDispose { tabReselectHandlers.remove(handler) }
}
}
You can then do what you want easily for example I do in deep screen to first allow scroll to top TabReselectHandler {
if (lazyGridState.firstVisibleItemIndex > 0) {
lazyGridState.scrollToItem(0)
return@TabReselectHandler true
}
false
} And in the root tabs TabReselectHandler {
activeNavigator?.let { childNavigator ->
if (childNavigator.stackSize > 1) {
childNavigator.goRoot()
return@TabReselectHandler true
}
}
false
} |
The message above solves the problem (thanks you Tolriq!) |
I've been using your library for a month or something, and I'm pretty satisfied of it. It's cool!
But there's a thing. I want my app to have the following behaviour: when user clicks on a tab in BottomNavigation and the tab isn't selected yet, the library just switches Tabs, but when the tab is already selected, I want my app to reset navigation state of the tab (i.e. pop navigator to root).
I tried to implement the behaviour myself though, but the problem is that I can't access almost anything from TabNavigator...
Did I miss something? Any help will be appreciated. Thanks in advance!
The text was updated successfully, but these errors were encountered: