Citut
Citut

Reputation: 907

How can I align widths of first column in a list of rows using Jetpack Compose

I am making a layout where a column contains up to 5 rows. Each row has three columns and I would like to have the width of the first column of each row be completely equal.

The first column in each row always takes up as much size as the text it contains, the size of the column doesn't scale to match the size of the biggest column in the list of rows.

Each row item:

fun GetRowItem(firstColumnText: String, secondColumnText: String, thirdColumnText: String) {
    Row(
        modifier = Modifier.padding(start = 4.dp, end = 4.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Column(
            modifier = Modifier.padding(end = 4.dp),
        ) {
            Text(
                text = firstColumnText
            )
        }
        Column(
            modifier = Modifier.padding(end = 4.dp),
        ) {
            Text(
                text = secondColumnText
            )
        }
        Column(
            modifier = Modifier.padding(end = 4.dp),
        ) {
            Text(
                text = thirdColumnText
            )
        }
    }
}

Then I have a parent that arranges the rows something like this:

Column(modifier = Modifier.fillMaxWidth().padding(start = 8.dp, end = 8.dp) {
    GetRowItem(firstColumnText = "short", secondColumnText = "something", thirdColumnText = "something")
    GetRowItem(firstColumnText = "Realy long ee", secondColumnText = "something", thirdColumnText = "something")
    GetRowItem(firstColumnText = "1", secondColumnText = "something", thirdColumnText = "something")
}

The output of this is not what I am looking for and I am struggling to see how to align the columns in each row item. It looks like InstrisicSize might be an option here, but I'm not sure how to get the max size of an arbitrary column in the list of rows and apply it to each column. The image below shows what I am getting versus what I am expecting. I only want to align the first columns, the rest don't matter.

expected vs actual

Upvotes: 7

Views: 3034

Answers (4)

user1185087
user1185087

Reputation: 4858

You can use a MutableState<Dp> which stores the maximum width. This width is set as minWidth for the first child composable of the row. The width is updated if there is any first child which exceeds the current width.

Note: The MutableState must be created in the scope of the parent (Column).

@Preview(showBackground = true)
@Composable
fun LabeledColumn() {
    Column {
        var firstColumnWidth by remember { mutableStateOf(0.dp) }
        val density = LocalDensity.current
        repeat(10) {
            Row {
                Text(
                    text = List(it + 1) { i -> "$i" }.joinToString(),
                    modifier = Modifier
                        .defaultMinSize(firstColumnWidth)
                        .onPlaced {
                            val widhtDp = density.run { it.size.width.toDp() }
                            firstColumnWidth = max(firstColumnWidth, widhtDp)
                        }
                )
                Text(text = "column 1", modifier = Modifier.weight(1f))
                Text(text = "column 2", modifier = Modifier.weight(1f))
            }
        }
    }
}

enter image description here

Upvotes: 0

OneDev
OneDev

Reputation: 617

maybe it could help

        Column(
            modifier = Modifier
                .fillMaxWidth()
                .weight(1f)
        ) {

        }

if you want the center column to be wider than the left and right column you can set the weight of the center column 2 and left and right 1, or you can set the width of columns for example to 100 dp or 200 dp, and set horizontalArrangement of your row to Arrangement.SpaceBetween to have some margin around the columns

Upvotes: 0

RaBaKa 78
RaBaKa 78

Reputation: 1465

I have found a way to solve your issue

Get Row Item

@Composable
fun GetRowItem(firstColumnText: String, secondColumnText: String, thirdColumnText: String, width: State<Int>, widthCallback: (Int) -> Unit) {

    val widthInDp = with(LocalDensity.current) {
        width.value.toDp()
    }

    Row(
        modifier = Modifier.padding(start = 4.dp, end = 4.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Column(
            modifier = Modifier.padding(end = 4.dp),
        ) {
            if (widthInDp == 0.dp) {
                Text(
                    text = firstColumnText,
                    modifier = Modifier.onGloballyPositioned {
                        widthCallback(it.size.width)
                    }
                )
            }else {
                Text(
                    text = firstColumnText,
                    modifier = Modifier.width(width = widthInDp)
                )
            }
        }

        Column(
            modifier = Modifier.padding(end = 4.dp),
        ) {
            Text(
                text = secondColumnText
            )
        }
        Column(
            modifier = Modifier.padding(end = 4.dp),
        ) {
            Text(
                text = thirdColumnText
            )
        }
    }

}

Parent code that holds the row

           Surface(color = MaterialTheme.colors.background) {
                    val width = remember {
                        mutableStateOf(0)
                    }
                    Column(
                        modifier = Modifier
                            .fillMaxSize()
                            .padding(start = 8.dp, end = 8.dp),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                            GetRowItem(firstColumnText = "short", secondColumnText = "something", thirdColumnText = "something", width = width) {
                                if (it > width.value) {
                                    width.value = it
                                }
                            }
                            GetRowItem(firstColumnText = "Realy long ee", secondColumnText = "something", thirdColumnText = "something", width = width) {
                                if (it > width.value) {
                                    width.value = it
                                }
                            }
                            GetRowItem(firstColumnText = "1", secondColumnText = "something", thirdColumnText = "something", width = width) {
                                if (it > width.value) {
                                    width.value = it
                                }
                            }
                        
                        }
                    }
                }
            }
        }

I'have added surface and modified column to fillMaxSize() so you can test this

Upvotes: 0

Scott Cooper
Scott Cooper

Reputation: 3099

An easy way to achieve this would be to give each of the columns the same weight.

Column(modifier = Modifier.weight(1f)){
 // text
}

Upvotes: 2

Related Questions