If we create state for list item like val state = remember(it) { mutableStateOf(ItemState()) } then we loose expanded state while scrolling.
If we lift up states generating higher before LazyColumn then expand state is saving properly
val states = items.map { remember(it) { mutableStateOf(ItemState()) } }
LazyColumn(modifier = Modifier.fillMaxSize()) {....
But when we expand an item, click the button, go to details screen and then go back to items we loose expanded state. What is the best way to save items state?
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
RememberStateTheme {
val navController = rememberNavController()
NavHost(navController, startDestination = "items") {
composable("items") {
Greeting(
onItemClick = { navController.navigate("details/$it") }
)
}
composable(
"details/{index}",
arguments = listOf(navArgument("index") { type = NavType.IntType })
) { backStackEntry ->
DetailsScreen(backStackEntry.arguments?.getInt("index") ?: -1)
}
}
}
}
}
}
@Composable
fun Greeting(
onItemClick: (Int) -> Unit
) {
val items = remember { (0..100).toList() }
Surface(color = MaterialTheme.colors.background) {
val states = items.map { remember(it) { mutableStateOf(ItemState()) } }
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(items) { item ->
// If we create state here like val state = remember(it) { mutableStateOf(ItemState()) }
// then we loose expanded state while scrolling
// If we lift up states generating higher before LazyColumn then expand state
// is saving properly
//
// But when we expand an item, click the button and then go back to items we loose
// expanded state
val state = states[item]
key(item) {
Item(index = item,
state = state.value,
onClick = { onItemClick(item) },
modifier = Modifier
.fillMaxSize()
.clickable {
state.value.changeState()
}
)
}
Divider()
}
}
}
}
@Composable
fun Item(
index: Int,
state: ItemState,
modifier: Modifier = Modifier,
onClick: () -> Unit
) {
Box(modifier = modifier) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.align(Alignment.Center)
) {
Text(
text = index.toString(),
modifier = Modifier.padding(16.dp)
)
if (state.expanded) {
Button(
onClick = onClick,
modifier = Modifier.padding(8.dp)
) {
Text(text = "Click me")
}
}
}
}
}
class ItemState {
val expanded: Boolean
get() = _expanded.value
private val _expanded = mutableStateOf(false)
fun changeState() {
_expanded.value = !_expanded.value
}
}
@Composable
fun DetailsScreen(
index: Int,
modifier: Modifier = Modifier
) {
Box(
modifier = modifier
.fillMaxSize()
.background(Color.Gray.copy(alpha = 0.3f))
) {
Text(
text = index.toString(),
modifier = Modifier.align(Alignment.Center)
)
}
}