Alexander Maryanovsky
05/16/2024, 9:49 AMvar selectedTab by remember { mutableIntStateOf(0) }
Tabs(..., onTabClicked = { selectedTab = it })
Box {
if (selectedTab == 0) {
FirstTabContent()
} else {
SecondTabContent()
}
}
Do I really need to provide my own SaveableStateRegistry
and manually save/restore it on every tab change?Nthily
05/16/2024, 10:00 AMrememberSaveable
should be enough 🤔Alexander Maryanovsky
05/16/2024, 10:00 AMColumn(Modifier.fillMaxSize()) {
var shownIndex by remember { mutableStateOf(0) }
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Button(onClick = { shownIndex = 0 }) { Text("Show First Panel")}
Button(onClick = { shownIndex = 1 }) { Text("Show Second Panel")}
}
Box(Modifier.fillMaxWidth().weight(1f)) {
if (shownIndex == 0) {
var text by rememberSaveable { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it })
} else {
Text("Screen 2")
}
}
}
Alexander Maryanovsky
05/16/2024, 10:01 AMAlexander Maryanovsky
05/16/2024, 10:02 AMprivate class TabsStateProvider {
private val stateByTabIndex = mutableMapOf<Int, Map<String, List<Any?>>>()
@Composable
fun provideSaveableTabStateRegistry(tabIndex: Int, content: @Composable () -> Unit) {
val state = stateByTabIndex.getOrPut(tabIndex) { mutableMapOf() }
val registry = remember(tabIndex) {
SaveableStateRegistry(state) { true }
}
CompositionLocalProvider(LocalSaveableStateRegistry provides registry) {
content()
}
DisposableEffect(tabIndex, registry) {
onDispose {
stateByTabIndex[tabIndex] = registry.performSave()
}
}
}
}
fun main() = singleWindowApplication {
Column(Modifier.fillMaxSize()) {
var shownIndex by remember { mutableStateOf(0) }
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Button(onClick = { shownIndex = 0 }) { Text("Show First Panel")}
Button(onClick = { shownIndex = 1 }) { Text("Show Second Panel")}
}
val tabState = remember { TabsStateProvider() }
Box(Modifier.fillMaxWidth().weight(1f)) {
tabState.provideSaveableTabStateRegistry(shownIndex) {
if (shownIndex == 0) {
var text by rememberSaveable { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it })
} else {
Text("Screen 2")
}
}
}
}
}
Albert Chang
05/16/2024, 10:10 AMval savableStateHolder = rememberSaveableStateHolder()
savableStateHolder.SaveableStateProvider(key = selectedTab) {
Content()
}
Nthily
05/16/2024, 10:12 AMColumn {
var text by rememberSaveable { mutableStateOf("") }
var shownIndex by remember { mutableIntStateOf(0) }
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
IconButton(onClick = { shownIndex = 0 }) { Text("Show First Panel")}
IconButton(onClick = { shownIndex = 1 }) { Text("Show Second Panel")}
}
Box(
Modifier
.fillMaxWidth()
.weight(1f)) {
if (shownIndex == 0) {
TextField(value = text, onValueChange = { text = it })
} else {
Text("Screen 2")
}
}
}
there's a simpler way to do it in this case, by hoisting the TextState above it so that the shownIndex recomposition doesn't affect its stateAlexander Maryanovsky
05/16/2024, 10:13 AMhere’s a simpler way to do it in this caseThat doesn’t work for a generic
TabbedPane
widget. I can’t ask the user to hoist all the state outside the widget.Alexander Maryanovsky
05/16/2024, 10:15 AMI think this is what you want.Indeed, that does the trick. Thanks.