I want to select one item of my LazyColumn and change the textcolor. How is it possible to identify which item is selected?
Code:
val items = listOf(Pair("A", 1), Pair("AA", 144), Pair("BA", 99))
var selectedItem by mutableStateOf(items[0])
LazyColumn {
this.items(items = items) {
Row(modifier = Modifier.clickable(onClick = {selectedItem = it}) {
if (selectedItem == it) {
Text(it.first, color = Color.Red)
} else {
Text(it.first)
}
}
}
}
Depending how I save it (with remember or without) they just highlight both if I click on one and not just the one I clicked the last.
As the name suggests, the difference between LazyColumn and LazyRow is the orientation in which they lay out their items and scroll. LazyColumn produces a vertically scrolling list, and LazyRow produces a horizontally scrolling list. The Lazy components are different to most layouts in Compose.
Android Compose – Enable Vertical Scroll for Column To enable Column to allow to scroll vertically when the height of the content inside Column is bigger than the allowed height/constraints, use Modifier. verticalScroll() for the Column modifier parameter.
A LazyColumn is a vertically scrolling list that only composes and lays out the currently visible items. It's similar to a Recyclerview in the classic Android View system.
You can use the the .selectable
modifier instead of .clickable
Something like:
data class Message(val id: Int,
val message : String)
val messages : List<Message> = listOf(...))
val listState = rememberLazyListState()
var selectedIndex by remember{mutableStateOf(-1)}
LazyColumn(state = listState) {
items(items = messages) { message ->
Text(
text = message.message,
modifier = Modifier
.fillMaxWidth()
.background(
if (message.id == selectedIndex)
Color.Red else Color.Yellow
)
.selectable(
selected = message.id == selectedIndex,
onClick = { if (selectedIndex != message.id)
selectedIndex = message.id else selectedIndex = -1})
)
}
}
In your case you can use:
var selectedItem by remember{mutableStateOf( "")}
LazyColumn {
this.items(items = items) {
Row(modifier = Modifier.selectable(
selected = selectedItem == it.first,
onClick = { selectedItem = it.first}
)
) {
if (selectedItem == it.first) {
Text(it.first, color = Color.Red)
} else {
Text(it.first)
}
}
}
}
Note that in the accepted answer, all the item views will be recomposed every time the selection changes, because the lambdas passed in onClick
and content
(of Row
) are not stable (https://developer.android.com/jetpack/compose/lifecycle#skipping).
Here's one way to do it so that only the deselected and selected items are recomposed:
@Composable
fun ItemView(index: Int, selected: Boolean, onClick: (Int) -> Unit){
Text(
text = "Item $index",
modifier = Modifier
.clickable {
onClick.invoke(index)
}
.background(if (selected) MaterialTheme.colors.secondary else Color.Transparent)
.fillMaxWidth()
.padding(12.dp)
)
}
@Composable
fun LazyColumnWithSelection(){
var selectedIndex by remember { mutableStateOf(0) }
val onItemClick = { index: Int -> selectedIndex = index}
LazyColumn(
modifier = Modifier.fillMaxSize(),
){
items(100){ index ->
ItemView(
index = index,
selected = selectedIndex == index,
onClick = onItemClick
)
}
}
}
Note how the arguments passed to ItemView
only change for the items whose selected state changes. This is because the onItemClick
lambda is the same all the time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With