I'm trying to position an element exactly like thi...
# compose
m
I'm trying to position an element exactly like this red box by offsetting it upwards by half of its size, but the problem with my naive approach (Using
Modifier.layout {}
) is that it pushes the text beneath the row (red box + button) by the same offset amount leaving a weird vertical gap in between. Obviously offsetting the text upwards as well by the same amount doesn't solve the problem because it just moves that gap after the text. what I want to do is basically the same as the second picture but without that blank gap at the bottom.
My approach:
Copy code
@Composable
fun Sample() {
    Box(
        modifier = Modifier
            .wrapContentSize()
            .background(Color.Blue)
    ) {
        Column(
            verticalArrangement = Arrangement.spacedBy(16.dp),
            modifier = Modifier
                .padding(top = 80.dp)
                .background(Color.White)
                .padding(horizontal = 16.dp)
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween
            ) {
                Box(
                    modifier = Modifier
                        .size(128.dp)
                        .layout { measurable, constraints ->
                            val placeable = measurable.measure(constraints)

                            val offsetY = -(placeable.height / 2)

                            layout(constraints.maxWidth, placeable.height) {
                                placeable.placeRelative(0, offsetY)
                            }
                        }
                        .background(Color.Red)
                )

                ElevatedButton(
                    onClick = { /*TODO*/ },
                    shape = RoundedCornerShape(16.dp),
                    colors = ButtonDefaults.elevatedButtonColors(
                        containerColor = MaterialTheme.colorScheme.primary,
                        contentColor = MaterialTheme.colorScheme.onPrimary
                    ),
                    modifier = Modifier.padding(vertical = 4.dp)
                ) {
                    Text(
                        text = "Button",
                        style = MaterialTheme.typography.labelLarge
                    )
                }
            }
            Text(
                text = "Text",
                color = Color.Black,
                fontSize = 32.sp
            )
        }
    }
}
I feel like there is an easy way, but I think I'm overcomplicating things.
g
Not sure if this is what you are trying to do, but this closely replicates the layout on the right.
Copy code
Box {
        Box(modifier = Modifier.background(Color.Blue).height(64.dp + 16.dp).fillMaxWidth())
        Column(
            verticalArrangement = Arrangement.spacedBy(16.dp),
            modifier = Modifier
                .padding(top = 16.dp)
                .padding(horizontal = 16.dp)
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.Bottom
            ) {
                Box(
                    modifier = Modifier.size(128.dp).background(Color.Red)
                )

                ElevatedButton(
                    onClick = { /*TODO*/ },
                    shape = RoundedCornerShape(16.dp),
                    colors = ButtonDefaults.elevatedButtonColors(
                        containerColor = MaterialTheme.colorScheme.primary,
                        contentColor = MaterialTheme.colorScheme.onPrimary
                    ),
                    modifier = Modifier.padding(vertical = 4.dp)
                ) {
                    Text(
                        text = "Button",
                        style = MaterialTheme.typography.labelLarge
                    )
                }
            }
            Text(
                text = "Text",
                color = Color.Black,
                fontSize = 32.sp
            )
        }
    }
thank you color 1
m
Unfortunately, it looks like the first picture which I don't want
It actually does work for this simple hardcoded values sample but the real usecase I want to use this for is a bit more involved which makes it the same as the first picture, I might take a deep look and see if i can tweak it to what i need
m
create a Column with Box + Text, and use offset(-boxHeight / 2)
wouldn’t that work
m
I've solved it already by tweaking the above code a bit, but using offset will not work(this is what I was actually using at the beginning), it will produce the same gap at the bottom as the second picture. This is probably due to the fact that
offset
doesn't affect layout.
g
placeable.place(), or variants, position where the Composable is drawn but doesn't change the size provided to layout(). In the original example, the top of the red box was placed above the top of its container by using a negative y-axis coordinate. The parent Row has no way of knowing this - it lays out content according to the size of its children, which are the values provided in the call to layout().
m
You have to offset both, obviously
m
@Greg Steckman Yes, you're right. I forgot about that when I thought
Modifier.offset
is a possible solution.
@myanmarking When I offset both elements I'm just moving that gap to the next item laid vertically, So I end up with a weird gap at the bottom when I reach the end of this vertical column, Also, The screenshot above shows a minimal example, The real screen where I'm using this has actually many more elements, so offsetting every element I add to the column is not ideal.