添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
不爱学习的番茄  ·  Spring Data ...·  4 周前    · 

我试着用 LazyVerticalGrid 来实现它,但Jetpack Compose不允许我把 LazyVerticalGrid 放在可垂直滚动的 Column 里面。

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

4 个评论
@CommonsWare 但 DataTable 已不再可用...
啊,我很抱歉。我忘了这个帖子是依靠谷歌直接删除的东西。
They look very useful though. I wonder why they removed them.
android
android-jetpack-compose
Kevin
Kevin
发布于 2021-06-26
3 个回答
nglauber
nglauber
发布于 2022-01-27
已采纳
0 人赞同

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

首先,你可以为你的表格定义一个单元格。

@Composable
fun RowScope.TableCell(
    text: String,
    weight: Float
    Text(
        text = text,
        Modifier
            .border(1.dp, Color.Black)
            .weight(weight)
            .padding(8.dp)

然后你可以用它来建造你的桌子。

@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)

Here is the result:

谢谢你的回答。 如果我想让标题单元格有足够的宽度给里面的内容,而不是固定的重量,我可以怎么做?我想我也发现了一个 LazyColumn 的问题。AndroidViews在它里面没有膨胀。
在这种情况下,你需要实现一个自定义的布局,它将测量列的宽度来设置它。文档可以帮助你解决这个问题... developer.android.com/jetpack/compose/layout#create-custom
天哪,我还是被自定义布局吓到了,哈哈。谢谢你指出来。我完全忘了这一点。
替换代码0】对于 Text() 似乎不支持到 androidx.compose.material:material:1.0.3 ?它不能为我编译。
如果你有多列,它也会水平滚动吗?
chRyNaN
chRyNaN
发布于 2022-01-27
0 人赞同

一个既支持固定列宽又支持可变列宽,并且可以水平和垂直滚动的实现方式如下。

@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)

这种实现方式的好处是提供了更大的灵活性和一个相对简单的API。然而,也有一些已知的注意事项,包括:可变宽度的列的性能较差,而且分栏必须在单元格一级完成。

对于可变宽度的列,它的性能并不高,因为它需要多个 "布局通道"。基本上,这个实现在一个LazyColumn中布置每个Row,测量每一行中的每个列单元,并将最大的宽度值存储在一个MutableState中。当某一列遇到较大的宽度值时,它将触发重新组合,将该列中的所有其他单元格调整为较大的宽度。这样一来,一列中的每个单元格都有相同的宽度(一行中的每个单元格都有相同的高度)。对于固定宽度的列,其性能应该与其他实现方式相当,因为它不需要多个 "布局传递"。

使用方法。

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

使用上述实现的重载可组合函数应该是相当容易创建的,例如让 "头行 "成为表中的第一行。

我可以在分页的情况下使用它吗?
user2416823
user2416823
发布于 2022-01-27
0 人赞同

我的解决方案并不完美,但至少水平滚动可以工作。这是我没有发现也没有想到的最好办法。我希望谷歌发布它自己的实现 数据表 . At the moment 数据表 is not implemented for Android. To set the width of the columns, you have to calculate their weights, but this calculation is not accurate.

private fun calcWeights(columns: List<String>, rows: List<List<String>>): List<Float> {
    val weights = MutableList(columns.size) { 0 }
    val fullList = rows.toMutableList()
    fullList.add(columns)
    fullList.forEach { list ->
        list.forEachIndexed { columnIndex, value ->
            weights[columnIndex] = weights[columnIndex].coerceAtLeast(value.length)
    return weights
        .map { it.toFloat() }
@Composable
fun SimpleTable(columnHeaders: List<String>, rows: List<List<String>>) {
    val weights = remember { mutableStateOf(calcWeights(columnHeaders, rows)) }
    Column(
        modifier = Modifier
            .horizontalScroll(rememberScrollState())
        /* HEADER */
        Row(modifier = Modifier.fillMaxWidth()) {
            columnHeaders.forEachIndexed { rowIndex, cell ->
                val weight = weights.value[rowIndex]
                SimpleCell(text = cell, weight = weight)
        /* ROWS  */
        LazyColumn(modifier = Modifier) {
            itemsIndexed(rows) { rowIndex, row ->
                    modifier = Modifier
                        .fillMaxWidth()
                    row.forEachIndexed { columnIndex, cell ->
                        val weight = weights.value[columnIndex]
                        SimpleCell(text = cell, weight = weight)
@Composable
private fun SimpleCell(
    text: String,
    weight: Float = 1f
    val textStyle = MaterialTheme.typography.body1
    val fontWidth = textStyle.fontSize.value / 2.2f // depends of font used(
    val width = (fontWidth * weight).coerceAtMost(500f)
    val textColor = MaterialTheme.colors.onBackground
    Text(
        text = text,
        maxLines = 1,
        softWrap = false,
        overflow = TextOverflow.Ellipsis,
        color = textColor,
        modifier = Modifier
            .border(0.dp, textColor.copy(alpha = 0.5f))
            .fillMaxWidth()