StuartDTO
StuartDTO

Reputation: 1061

Overlap two Box jetpack compose

I'm trying to overlap two Box or perhaps is better to use Row on this case.

My design is one Row overlapped with another one, and I've wrapped it on a Column, is that correct?

This is the design, what I'd like to have is the rectangle of the top be the same size of the one below and then move it some pixels as you can see in the image, but they should have the same width but not the same height.

enter image description here

Is it okay if the hierarchy is :

Column 
  Box (the one of the top)
    Row
  Box (the one of the bottom)
    Row (inside there is text and it's all the same align)

......

Upvotes: 17

Views: 35128

Answers (7)

Harish Reddy
Harish Reddy

Reputation: 1002

You can also use the offset like this below to achieve the image overlay effort like this.

      Box(
            modifier = Modifier
                .wrapContentWidth()
                .wrapContentHeight()
        ) {

            AsyncImage(
                model = ImageRequest.Builder(LocalContext.current)
                    .data(imageOne)
                    .crossfade(true)
                    .build(),
                contentDescription = nameOne,
                contentScale = ContentScale.Crop,
                modifier = Modifier
                    .size(55.dp)
                    .clip(CircleShape)
                    .align(Alignment.Center)

            )

            AsyncImage(
                model = ImageRequest.Builder(LocalContext.current)
                    .data(imageTwo)
                    .crossfade(true)
                    .build(),
                contentDescription = nameOne,
                contentScale = ContentScale.Crop,
                modifier = Modifier
                    .size(55.dp)
                    .offset(x = 5.dp, y = 5.dp)
                    .align(Alignment.Center)
                    .clip(CircleShape)

            )
        }

X = horizontal, Y = Vertical

enter image description here

Upvotes: 5

Martyna Maron
Martyna Maron

Reputation: 673

To have two boxes or any other composables overlap in this way you can use spacedBy method for the arrangement, either on a Row or Column and pass a negative value. This is supported by the Android docs as well.

For example:

fun OverlappingBoxesPreview() {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.padding(20.dp),
        verticalArrangement = Arrangement.spacedBy((-30).dp),
    ) {
        Box(
            modifier = Modifier
                .size(100.dp)
                .background(Color.Red),
        )

        Box(
            modifier = Modifier
                .size(80.dp)
                .background(Color.Green),
        )

    }
}

Will produce:

enter image description here

Upvotes: 6

newDeveloper
newDeveloper

Reputation: 35

I think you must use "matchParentSize" modifier that is avaliabele inside BoxScope, I mean inside Box composable, that modifer measure other children size except itself when it has join the composable at first time to apply the same size to itself.

you can see this modifier in documentation https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/BoxScope#(androidx.compose.ui.Modifier).matchParentSize()

Upvotes: 1

dmastra
dmastra

Reputation: 459

This is way using BoxWithConstraints and not using fixed width and height:

BoxWithConstraints(
    Modifier
        .background(color = Color.Blue)
        .padding(20.dp)) {

    val boxWidth = this.maxWidth
    Box(
        modifier = Modifier
            .width(boxWidth - 10.dp)
            .background(Color.Red)
    ) {
        Text(text = "Hello Android")
    }
    Column() {
        Spacer(modifier = Modifier
            .height(10.dp)
            .width(10.dp))
        Row( ) {
            Spacer(modifier = Modifier.width(10.dp))
            Box(
                modifier = Modifier
                    .width(boxWidth)
                    .zIndex(2f)
                    .background(Color.Yellow)
            ) {
                Text("aa", modifier = Modifier.background(color = Color.Green))
            }
        }
    }
}

two boxes same width

Upvotes: 13

Skizo-ozᴉʞS ツ
Skizo-ozᴉʞS ツ

Reputation: 20646

I've faced with this some days ago and I solved it using ConstraintLayout.

What I had to do is :

  1. Add implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02" to build.gradle
  2. Wrap every Box in a ConstraintLayout { .. }
  3. Inside each Box add a Modifier.constrainAs to align the Top Bottom Start End as you want.
  4. If you want the first box be the same width as the second one without hardcoding the dps you should use width = Dimension.fillToConstraints

fillToConstraints - the layout will expand to fill the space defined by its constraints in that dimension.

Basic example without hard-coding :

ConstraintLayout() {
            val (title, description) = createRefs()
            Box(
                modifier = Modifier
                    .padding(start = 28.dp)
                    .background(color = Red)
                    .padding(
                        horizontal = 16.dp,
                    )
                    .constrainAs(title) {
                        top.linkTo(parent.top)
                        start.linkTo(parent.start)
                        end.linkTo(parent.end)
                        width = Dimension.fillToConstraints
                    }
            ) {
                Text(text = "Hello World")
            }

            Box(
                modifier = Modifier
                    .padding(end = 4.dp)
                    .background(Color.Magenta)
                    .padding(bottom = 5.dp, start = 8.dp, end = 16.dp, top = 4.dp)
                    .constrainAs(description) {
                        top.linkTo(title.top, margin = 16.dp)
                        start.linkTo(parent.start)
                        end.linkTo(parent.end)
                        bottom.linkTo(parent.bottom)
                    }
            ) {
                Text(text = "Skizo-ozᴉʞS rules")
            }
        }

Now you have to play with the padding according to your UI and adapt it, result is something like this :

enter image description here

Upvotes: 15

RaBaKa 78
RaBaKa 78

Reputation: 1465

You can achieve this in many ways,

@Composable
fun BoxOverBox() {
    Box(
        modifier = Modifier.fillMaxSize()
            .background(Color.White),
        contentAlignment = Alignment.Center
    ) {
        Box(
            modifier = Modifier
                .width(200.dp)
                .height(50.dp)
                .background(Color.Red)
        )
        Box(
            modifier = Modifier
                .width(200.dp)
                .height(50.dp)
                .zIndex(2f)
                .graphicsLayer {
                    translationX = -50f
                    translationY = 50f
                }
                .background(Color.Blue)
        )
    }
}

Upvotes: 4

daniyelp
daniyelp

Reputation: 1265

In order for the Composables to overlap, you should put them in the same Box. Try this out:

Box(modifier = Modifier.size(width = 300.dp, height = 100.dp)) {
    Row(modifier = Modifier
        .size(width = 200.dp, height = 50.dp)
        .background(color = Color.Blue)
        .align(Alignment.TopEnd)) {}
    Row(modifier = Modifier
        .size(width = 200.dp, height = 70.dp)
        .background(color = Color.Red)
        .align(Alignment.BottomStart)) {}
}

Upvotes: 11

Related Questions