Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpack

Aligning a field on the bottom of a box


I'm working on creating a layout in compose, and I'm facing challenges in positioning elements as desired. Specifically, I'm trying to design a container with an image, occupying half of the screen height. Within this container, I aim to include a couple of text views, where one should be centered vertically, and the other positioned above it. The other thing is I want that TextField to be above the center divider, but it stays in the middle of the box with this code:

Composable
private fun CodeLayout(viewModel: HomeViewModel) {
    MainLayout(viewModel = viewModel)
    Column {
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .fillMaxHeight(0.5f)
                .background(Color.White.copy(alpha = 1f))
                .padding(16.dp)
        ) {
            Image( ... )

            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(start = 10.dp, end = 10.dp)
            ) {
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(top = 5.dp, end = 10.dp),
                    horizontalArrangement = Arrangement.End
                ) {
                    Text( .... )
                }

                Column(
                    modifier = Modifier
                        .fillMaxHeight()
                        .align(Alignment.CenterVertically)
                ) {
                   *T1*Text( .... )
                }

                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                ) {
                    *T2*Text( .... )
                }
            }

            Box(
              modifier = Modifier
                  .fillMaxWidth()
            ) {
            OtpTextField(
                modifier = Modifier
                    .align(Alignment.TopCenter)
                    .padding(16.dp),
                otpText = otpValue,
                otpCount = 6,
                onOtpTextChange = { newOtp, isComplete ->
                    otpValue = newOtp
                    if (isComplete) {
                        //
                    }
                },
                onOtpCompleted = {
                    //
                }
            )

            Divider(
                color = Color.Blue,
                thickness = 3.dp,
                modifier = Modifier
                    .align(Alignment.BottomCenter)
            )
        }
    }
}

Solution

  • The easiest way to achieve what you're trying to do is to use ConstraintLayout.

    Necessary dependency:

    implementation("androidx.constraintlayout:constraintlayout-compose:1.0.1")
    

    Example implementation:

    @Composable
    fun CodeLayout() {
        Column {
            ConstraintLayout(
                modifier = Modifier
                    .fillMaxWidth()
                    .fillMaxHeight(0.5f)
                    .background(Color.White.copy(alpha = 1f))
    //                .padding(16.dp)
            ) {
                val (topText, centerText, bottomTextField, bottomDivider) = createRefs()
                Text(
                    text = "T2 above T1",
                    modifier = Modifier.constrainAs(topText) {
                        centerHorizontallyTo(parent)
                        bottom.linkTo(centerText.top, margin = 16.dp)
                    }
                )
                Text(
                    text = "T1 centered vertically",
                    modifier = Modifier.constrainAs(centerText) {
                        centerHorizontallyTo(parent)
                        centerVerticallyTo(parent)
                    }
                )
                TextField(
                    modifier = Modifier.constrainAs(bottomTextField) {
                        centerHorizontallyTo(parent)
                        bottom.linkTo(bottomDivider.top, margin = 16.dp)
                    },
                    value = "OTP text field",
                    onValueChange = {},
                )
                Divider(
                    color = Color.Blue,
                    thickness = 3.dp,
                    modifier = Modifier.constrainAs(bottomDivider) {
                        bottom.linkTo(parent.bottom)
                    }
                )
            }
        }
    }