20

So I am trying to create a Chess Board using JetPack compose & have managed to draw the layout a bit. But, Now I have issue that I want the board square to have a equal height as width. I want it to be perfect square.

Note: I don't want to give any fix width or height. I want to fit squares in the screens width & then each squares' height should be as much as the width.

What I have tried:

@ExperimentalFoundationApi
class PlayGameActivity : BaseActivity() {
    val darkSquare = Color(0xFF779556)
    val lightSquare = Color(0xFFEBECD0)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Column {
                Board()
            }
        }
    }

    @Composable
    fun Board() {
        Column {
            for (i in 0 until 8) {
                Row {
                    for (j in 0 until 8) {
                        val isLightSquare = i % 2 == j % 2
                        val squareColor = if (isLightSquare) lightSquare else darkSquare
                        Box(
                            modifier = Modifier
                                .weight(1f)
                                .background(squareColor)
                        ) {
                            Text(text = "${i + j}")
                        }
                    }
                }
            }
        }
    }

}

It gives me following result.

Chess Box Layout

What I expect it to look like:

Chess Box Expectations

Any Idea how I can calculate width & set it same as width of the square?

Mayur Gajra
  • 8,285
  • 6
  • 25
  • 41

2 Answers2

59

A simpler solution is to set the aspectRatio attribute on your modifier:

@Composable
fun Board() {
    Column {
        for (i in 0 until 8) {
            Row {
                for (j in 0 until 8) {
                    val isLightSquare = i % 2 == j % 2
                    val squareColor = if (isLightSquare) lightSquare else darkSquare
                    Box(
                        modifier = Modifier
                            .weight(1f)
                            .aspectRatio(1f)
                            .background(squareColor)
                    ) {
                        Text(text = "${i + j}")
                    }
                }
            }
        }
    }
}
Francesc
  • 25,014
  • 10
  • 66
  • 84
9

You can use the layout modifier to adapt the dimension of the each Box.

Something like:

Column {
    for (i in 0 until 8) {
        Row {
            for (j in 0 until 8) {
                val isLightSquare = i % 2 == j % 2
                val squareColor = if (isLightSquare) Yellow else Red
                Box(
                    modifier = Modifier
                        .weight(1f)
                        .background(squareColor)

                        .layout(){ measurable, constraints ->
                            // Measure the composable
                            val placeable = measurable.measure(constraints)

                            //get the current dimension to assign width=height
                            val currentWidth = placeable.width
                            
                            //assign the dimension and the position
                            layout(currentWidth, currentWidth) {
                                // Where the composable gets placed
                                placeable.placeRelative(0, 0)
                            }
                        }
                    ,
                ) {
                    Text(text = "${i + j}")
                }
            }
        }
    }
}

enter image description here

In your case, if you know the board width you can also use something like:

var size by remember { mutableStateOf (Size.Zero) }
val width = with(LocalDensity.current){
        (size.width/8).toDp()
}
Column(
        Modifier.fillMaxSize()
            .onGloballyPositioned { coordinates ->
              size = coordinates.size.toSize()
    }) {
             //...
                    Box(
                        modifier = Modifier
                            .size(
                                width = width,
                                height = width,
                            )
                            .background(squareColor)
                        ,
                    )
             //...
                
    }
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • perhaps you can help me out with this https://stackoverflow.com/questions/70799640/overlap-two-box-jetpack-compose – StuartDTO Jan 24 '22 at 08:35
  • Using the `onGloballyPositioned` seems to be the most generic solution for me, although I had to make sure to give it the proper size constraints (in my case I had another view next to this that also wanted to have space, so I had to use `Modifier.weight(0.7f).fillMaxHeight()` to get it to calculate correctly) – Simon Forsberg May 22 '23 at 19:48