skip to Main Content

I run Code A and get Result A.

How can I make the two buttons the same width?

BTW, you know different string has different width, you can’t write a hard code such as Modifier.width(100.dp).

Code A

        Row(
            modifier =Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.Center
        ) {
            Button(
                modifier = Modifier,
                onClick = { }
            ) {
                Text("Short")
            }

            Button(
                modifier = Modifier.padding(start = 10.dp),
                onClick = { }
            ) {
                Text("This is a Long")
            }
        }

Result A

enter image description here

2

Answers


  1. You can achieve setting width of long button to short one as in the answer described here with SubcomposeLayout.

    What you need to do is subcompose your layout to check which element has longer width then subcompose your items again with this width as minimum constraint.

    @Composable
    private fun SubcomposeRow(
        modifier: Modifier = Modifier,
        paddingBetween: Dp = 0.dp,
        content: @Composable () -> Unit = {},
    ) {
        val density = LocalDensity.current
    
        SubcomposeLayout(modifier = modifier) { constraints ->
    
            var subcomposeIndex = 0
    
            val spaceBetweenButtons = with(density) {
                paddingBetween.roundToPx()
            }
    
            var placeables: List<Placeable> = subcompose(subcomposeIndex++, content)
                .map {
                    it.measure(constraints)
                }
    
            var maxWidth = 0
            var maxHeight = 0
            var layoutWidth = 0
    
            placeables.forEach { placeable: Placeable ->
                maxWidth = placeable.width.coerceAtLeast(maxWidth)
                    .coerceAtMost(((constraints.maxWidth - spaceBetweenButtons) / 2))
                maxHeight = placeable.height.coerceAtLeast(maxHeight)
            }
    
    
            layoutWidth = maxWidth
    
            // Remeasure every element using width of longest item using it as min width
            // Our max width is half of the remaining area after we subtract space between buttons
            // and we constraint its maximum width to half width minus space between
            if (placeables.isNotEmpty() && placeables.size > 1) {
                placeables = subcompose(subcomposeIndex, content).map { measurable: Measurable ->
                    measurable.measure(
                        constraints.copy(
                            minWidth = maxWidth,
                            maxWidth = ((constraints.maxWidth - spaceBetweenButtons) / 2)
                                .coerceAtLeast(maxWidth)
                        )
                    )
                }
    
                layoutWidth = (placeables.sumOf { it.width } + spaceBetweenButtons)
                    .coerceAtMost(constraints.maxWidth)
    
                maxHeight = placeables.maxOf { it.height }
            }
    
            layout(layoutWidth, maxHeight) {
                var xPos = 0
                placeables.forEach { placeable: Placeable ->
                    placeable.placeRelative(xPos, 0)
                    xPos += placeable.width + spaceBetweenButtons
                }
            }
        }
    }
    

    you can change this layouWidth with constraints.maxWidth if you want it to occupy available space.

    Then, instead of setting them from beginning of Composable you need to have your algorithm for laying them out at 0 y position and x position from beginning of the Composable if you want to have different spacings.

    placeable.placeRelative(xPos, 0)

    Usage

    @Composable
    private fun Sample() {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(10.dp)
        ) {
    
            Spacer(modifier = Modifier.height(20.dp))
    
            SubcomposeRow(
                modifier = Modifier.background(Color.LightGray).border(3.dp, Color.Green),
                paddingBetween = 20.dp
            ) {
                Button(
                    modifier = Modifier,
                    onClick = { }
                ) {
                    Text("Short")
                }
    
                Button(
                    modifier = Modifier,
                    onClick = { }
                ) {
                    Text("This is a Long")
                }
            }
    
            Spacer(modifier = Modifier.height(20.dp))
    
            SubcomposeRow(
                modifier = Modifier.background(Color.LightGray).border(3.dp, Color.Green),
                paddingBetween = 20.dp
            ) {
                Button(
                    modifier = Modifier,
                    onClick = { }
                ) {
                    Text("Short")
                }
    
                Button(
                    modifier = Modifier,
                    onClick = { }
                ) {
                    Text("This is a Long a button with text")
                }
            }
        }
    }
    

    Result

    enter image description here

    Login or Signup to reply.
  2. If you are interested in both buttons splitting the full space and being equal in width, you can use weight modifier

    Row(modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
            Button(onClick = { /*TODO*/ }, modifier = Modifier.weight(1f)) {
                Text(text = "Next")
            }
    
            Button(onClick = { /*TODO*/ }, modifier = Modifier.weight(1f)) {
                Text(text = "Previous")
            }
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search