I am new to Kotlin and Jetpack Compose. I am trying to display data from a data class depending on the row that the user clicks. The way I have it set up now is the data is remembered, but the user has to click the text box, and then click the row to get the data to show up in the card. It is set up like rows in a table.
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.LinearOutSlowInEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusModifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun ResultsBody(results: List<Result>) {
// Column (
// modifier = Modifier
// .padding(16.dp)
// .verticalScroll(rememberScrollState())
// .semantics { contentDescription = "SpeedTest Screen" }
// ){
// Text("Results Screen")
// }
TableScreen(results)
}
@Composable
fun TableCell(
text: String,
){
Text(
text = text,
Modifier
.padding(8.dp)
, color = Color.White,
fontSize = 20.sp
)
}
@Composable
fun Header(
text: String
){
Text(
text = text,
Modifier
.padding(8.dp)
, color = Color.Black,
textAlign = TextAlign.Justify,
fontSize = 20.sp
)
}
@Composable
fun TableScreen(resList : List<Result>) {
// The LazyColumn will be our table.
val openModule = remember { mutableStateOf(false) }
var selectedRow by remember { mutableStateOf<Result?>(null) }
LazyColumn(
Modifier
.fillMaxSize()
) {
// Here is the header
item {
Row(
Modifier
.background(Color.Gray)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
)
{
Header(text = "Date")
Header(text = "Up")
Header(text = "Down")
Header(text = "Latency")
Header(text = "Video")
Header(text = "MOS")
}
}
// Here are all the lines of the table.
items(resList) {
Divider(color = Color.LightGray, thickness = 1.dp)
Row(
Modifier
.fillMaxWidth()
.clickable { openModule.value = true },
horizontalArrangement = Arrangement.SpaceEvenly
) {
Text(
text = "${it.name} ",
Modifier
.padding(8.dp)
.clickable(onClick = { selectedRow = it }),
color = Color.White,
fontSize = 20.sp
)
Text(
text = "${it.upVal} ",
Modifier
.padding(8.dp)
.clickable(onClick = { selectedRow = it }),
color = Color.White,
fontSize = 20.sp
)
Text(
text = "${it.downVal} ",
Modifier
.padding(8.dp)
.clickable(onClick = { selectedRow = it }),
color = Color.White,
fontSize = 20.sp
)
Text(
text = "${it.latency} ",
Modifier
.padding(8.dp)
.clickable(onClick = { selectedRow = it }),
color = Color.White,
fontSize = 20.sp
)
Text(
text = "${it.video} ",
Modifier
.padding(8.dp)
.clickable(onClick = { selectedRow = it }),
color = Color.White,
fontSize = 20.sp
)
Text(
text = "${it.MOS} ",
Modifier
.padding(8.dp)
.clickable(onClick = { selectedRow = it }),
color = Color.White,
fontSize = 20.sp
)
// TableCell(text = "${it.upVal}")
// TableCell(text = "${it.downVal}")
// TableCell(text = "${it.latency}")
// TableCell(text = "${it.video}")
// TableCell(text = "${it.MOS}")
}
}
}
//Here opens the card with more information if the text in the row is clicked and the state is not null
if (openModule.value && selectedRow?.equals(null) == false) {
Card(
modifier = Modifier
.fillMaxSize()
) {
Column {
selectedRow?.let {
//If state is not null display data
Text(text = "Latitude: ${it.latitude}")
Text(text = "Longitude: ${it.longitude}")
}
}
}
}
}
How can I get the data corresponding to a specific row to show in the card on the click of the row? Is that possible?
CodePudding user response:
Having a click handler on your Row AND on each item isn't needed. You need to remove the click handler from the Row and modify the line of code that displays the card. You don't need the openModule
variable. Also, your click handler for the Text items may require you to modify your selectedRow variable like this:
var selectedRow by remember { mutableStateOf<Result?>(null) }.apply { this.value }
Calling this.value
is often necessary for click events in order to force a recompose. But you can try it without the apply
call and see if it works.
I removed most of your code to make it easier to focus on what you need to change:
@Composable
fun TableScreen(resList : List<Result>) {
// The LazyColumn will be our table.
var selectedRow by remember { mutableStateOf<Result?>(null) }.apply { this.value }
LazyColumn(
Modifier
.fillMaxSize()
) {
// Here are all the lines of the table.
items(resList) {
Divider(color = Color.LightGray, thickness = 1.dp)
Row(
Modifier
.fillMaxWidth()
horizontalArrangement = Arrangement.SpaceEvenly
) {
Text(
text = "${it.name} ",
Modifier
.padding(8.dp)
.clickable(onClick = { selectedRow = it }),
color = Color.White,
fontSize = 20.sp
)
}
}
}
//Here opens the card with more information if the text in the row is clicked and the state is not null
if (selectedRow != null) {
Card(
modifier = Modifier
.fillMaxSize()
) {
Column {
selectedRow?.let {
//If state is not null display data
Text(text = "Latitude: ${it.latitude}")
Text(text = "Longitude: ${it.longitude}")
}
}
}
}
}