如何在 Jetpack Compose 中创建表?

Kev*_*vin 36 android android-jetpack-compose

我想创建表视图(如下所示)来显示我拥有的数据。

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
一个标题另一个标题
第一的
第二
\n
\n

我尝试使用LazyVerticalGrid它来实现它,但 Jetpack Compose 不允许我放入LazyVerticalGrid可垂直滚动的Column.

\n

已经两天了,我真的没有主意了。

\n

ngl*_*ber 55

据我所知,没有内置组件。但实际上很容易对同一列的所有行LazyColumn使用相同的方法。 看这个例子:weight

首先,您可以为表格定义一个单元格:

@Composable
fun RowScope.TableCell(
    text: String,
    weight: Float
) {
    Text(
        text = text,
        Modifier
            .border(1.dp, Color.Black)
            .weight(weight)
            .padding(8.dp)
    )
}
Run Code Online (Sandbox Code Playgroud)

然后你可以用它来构建你的表:

@Composable
fun TableScreen() {
    // Just a fake data... a Pair of Int and String
    val tableData = (1..100).mapIndexed { index, item ->
        index to "Item $index" 
    }
    // Each cell of a column must have the same weight. 
    val column1Weight = .3f // 30%
    val column2Weight = .7f // 70%
    // The LazyColumn will be our table. Notice the use of the weights below
    LazyColumn(Modifier.fillMaxSize().padding(16.dp)) {
        // Here is the header
        item {
            Row(Modifier.background(Color.Gray)) {
                TableCell(text = "Column 1", weight = column1Weight)
                TableCell(text = "Column 2", weight = column2Weight)
            }
        }
        // Here are all the lines of your table.
        items(tableData) {
            val (id, text) = it
            Row(Modifier.fillMaxWidth()) {
                TableCell(text = id.toString(), weight = column1Weight)
                TableCell(text = text, weight = column2Weight)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

在此输入图像描述

  • 天哪,我仍然被自定义布局吓到了哈哈。感谢您指出。我完全忘记了。 (3认同)
  • 如果你有多列,它也会水平滚动吗? (2认同)

chR*_*NaN 17

支持固定和可变列宽,并且可水平和垂直滚动的实现如下所示:

@Composable
fun Table(
    modifier: Modifier = Modifier,
    rowModifier: Modifier = Modifier,
    verticalLazyListState: LazyListState = rememberLazyListState(),
    horizontalScrollState: ScrollState = rememberScrollState(),
    columnCount: Int,
    rowCount: Int,
    beforeRow: (@Composable (rowIndex: Int) -> Unit)? = null,
    afterRow: (@Composable (rowIndex: Int) -> Unit)? = null,
    cellContent: @Composable (columnIndex: Int, rowIndex: Int) -> Unit
) {
    val columnWidths = remember { mutableStateMapOf<Int, Int>() }

    Box(modifier = modifier.then(Modifier.horizontalScroll(horizontalScrollState))) {
        LazyColumn(state = verticalLazyListState) {
            items(rowCount) { rowIndex ->
                Column {
                    beforeRow?.invoke(rowIndex)

                    Row(modifier = rowModifier) {
                        (0 until columnCount).forEach { columnIndex ->
                            Box(modifier = Modifier.layout { measurable, constraints ->
                                val placeable = measurable.measure(constraints)

                                val existingWidth = columnWidths[columnIndex] ?: 0
                                val maxWidth = maxOf(existingWidth, placeable.width)

                                if (maxWidth > existingWidth) {
                                    columnWidths[columnIndex] = maxWidth
                                }

                                layout(width = maxWidth, height = placeable.height) {
                                    placeable.placeRelative(0, 0)
                                }
                            }) {
                                cellContent(columnIndex, rowIndex)
                            }
                        }
                    }

                    afterRow?.invoke(rowIndex)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这种实现的好处是提供了更大的灵活性和相对简单的 API。然而,有一些已知的警告,包括:可变宽度列的性能较差,并且必须在单元格级别上进行列分隔。

对于可变宽度列,它的性能不如需要多个“布局通道”。本质上,此实现将每个布局放在Rowa 中LazyColumn,测量每行中的每个列单元格并将最大宽度值存储在 a 中MutableState。当某列遇到较大的宽度值时,它将触发重组,将该列中的所有其他单元格调整为较大的宽度。这样,列中的每个单元格都具有相同的宽度(行中的每个单元格都具有相同的高度)。对于固定宽度的列,性能应该与其他实现相当,因为它不需要多个“布局过程”。

用法:

Table(
    modifier = Modifier.matchParentSize(),
    columnCount = 3,
    rowCount = 10,
    cellContent = { columnIndex, rowIndex ->
        Text("Column: $columnIndex; Row: $rowIndex")
    })
Run Code Online (Sandbox Code Playgroud)

使用上述实现的重载可组合函数的创建应该相当简单,例如将“标题行”作为表中的第一行。