1

I have created a custom layout to create a hexagonal grid, however, when I place the grid with other elements, for example inside a Row or Column, the grid won't update its position and stays on the top left corner of the map.

Here is my code:

import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.GenericShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import com.example.mygame.ui.theme.MyGameTheme

private val HexagonalShape = GenericShape { size, _ ->
    moveTo(size.width / 2f, 0f)
    lineTo(size.width, size.height / 4f)
    lineTo(size.width, 3 * size.height / 4f)
    lineTo(size.width / 2f, size.height)
    lineTo(0f, 3 * size.height / 4f)
    lineTo(0f, size.height / 4f)
}


@Composable
fun StandardTile(color: Color) {
    Box(
        modifier = Modifier
            .padding(horizontal = 1.dp, vertical = 1.dp)
            .wrapContentSize(Alignment.Center)
            .size(50.dp)
            .clip(HexagonalShape)
            .background(color)
            .clickable { /* TODO */ }
            .border(
                width = 1.dp,
                brush = SolidColor(Color.Black),
                shape = HexagonalShape
            )
    ) { }
}

@Composable
fun Grid(
    modifier: Modifier,
    lineLength: Int,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        val placeables = measurables.map { measurable ->
            measurable.measure(constraints)
        }

        layout(constraints.maxWidth, constraints.maxHeight) {
            var yPosition = 0
            var xPosition = 0
            val index = mutableListOf(0, 0)

            placeables.forEach { placeable ->
                placeable.placeRelative(x = xPosition, y = yPosition)
                if (index[0] != lineLength - 1) {
                    index[0]++
                    xPosition += placeable.width
                } else {
                    xPosition = if (index[1] % 2 == 0) placeable.width / 2  else 0
                    yPosition += 3 * placeable.height / 4
                    index[0] = 0
                    index[1]++
                }
            }
        }
    }
}


@Preview
@Composable
fun ShapePreview() {
    MyGameTheme {
        ConstraintLayout {
            val (gridRef, leftMenu) = createRefs()

            val margin = 0.10f
            val leftConstraint = createGuidelineFromStart(fraction = margin)
            val rightConstraint = createGuidelineFromEnd(fraction = margin)

            Column(
                modifier = Modifier
                    .constrainAs(gridRef) {
                        linkTo(start = rightConstraint, end = leftConstraint)
                        start.linkTo(rightConstraint)

                    }
                    .fillMaxWidth()) {

                Grid(
                    modifier = Modifier,
                    lineLength = 8
                ) {
                    for (i in 1..64) {
                        StandardTile(Color.Blue)
                    }
                }

            }

            val leftMenuScrollState = rememberScrollState()
            Column(
                modifier = Modifier
                    .constrainAs(leftMenu) {
                        linkTo(start = parent.start, end = leftConstraint)
                        start.linkTo(parent.start)
                    }
                    .background(Color.Black)
                    .fillMaxWidth(fraction = margin)
                    .fillMaxHeight()
                    .verticalScroll(leftMenuScrollState)
            ) {
                Text("Help Please, (this is inside the left menu btw)")
            }
        }
    }
}

As you can see that I am using a ConstraintLayout. The relative position of the grid won't change and I don't know why, and I am having the same issue when I am using a row or column.

So here is my question, how do I implement it so that the grid goes to its relative attributed place and not at the top left corner and what's the reason for the same?

There is a post here that might answer my question but I'm not sure how to implement it in my case.

Levi
  • 187
  • 2
  • 17
recouer
  • 45
  • 7

1 Answers1

1

Use width = Dimension.fillToConstraints in addition to specifying start and end constraint on grid.

Also, in your code leftContraint (constraint from parent's start) was used for end and rightConstraint (constraint from parent's end) for start. Just swapped those two.

Column(
    modifier = Modifier
        .constrainAs(gridRef) {
            // corrected start and end constraints
            linkTo(start = leftConstraint, end = rightConstraint)
            width = Dimension.fillToConstraints
        }
) {

    Grid(
        modifier = Modifier,
        lineLength = 8
    ) {
        for (i in 1..64) {
            StandardTile(Color.Blue)
        }
    }

}
Om Kumar
  • 1,404
  • 13
  • 19