Bincy Baby
Bincy Baby

Reputation: 4743

Convert XML Constraint Layout to Jetpack Compose - Chain Style, Bias

I am trying to create a specific layout with two views: a TextView and an ImageView. The TextView is dynamic, meaning the length of the text can vary. If the length of the text is less than the width of the device, the ImageView should align to the end of the TextView. However, if the length of the text exceeds the width of the device, the ImageView should be positioned at the end of the device's width. The text can span multiple lines, depending on the content.

I'm just starting with Jetpack Compose and have created a layout using XML's ConstraintLayout. I'm trying to convert this layout to Jetpack Compose, but I'm unsure about the equivalent methods for layout_constraintHorizontal_bias, layout_constraintHorizontal_chainStyle, and layout_constrainedWidth in Jetpack Compose.

Here is the complete XML code that I'm working with:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constrainedWidth="true"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/image"
        android:text="lorem epsum loremsum loremlorem epsum loremsum loremlorem epsum loremsum loremlorem epsum loremsum loremlorem epsum loremsum lorem"
        app:layout_constraintStart_toStartOf="parent"/>
    <ImageView
        android:id="@+id/image"
        android:layout_width="14dp"
        android:layout_height="14dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@id/textview"
        app:layout_constraintBottom_toBottomOf="@id/textview"
        app:layout_constraintStart_toEndOf="@+id/textview"
        android:src="@drawable/ic_information_grey"/>

</androidx.constraintlayout.widget.ConstraintLayout>

What I tried is:

@Composable
fun CustomLayout(inputText: String) {
    ConstraintLayout(modifier = Modifier.fillMaxWidth()) {
    val (text, image) = createRefs()

    val chain = createHorizontalChain(text,image, chainStyle = ChainStyle.Packed(0F))
    constrain(chain){
        start.linkTo(text.start)
        end.linkTo(image.end)
    }
    Text(
        text = inputText,
        modifier = Modifier
            .constrainAs(text) {
                start.linkTo(parent.start)
                end.linkTo(image.start)
                top.linkTo(parent.top)
                width = Dimension.preferredWrapContent
            }.wrapContentSize()
    )

    Image(
        painter = painterResource(id = R.drawable.ic_information_grey),
        contentDescription = null,
        modifier = Modifier
            .size(14.dp)
            .constrainAs(image) {
                end.linkTo(parent.end)
                top.linkTo(text.top)
                start.linkTo(text.end)
                width = Dimension.wrapContent
            }.wrapContentSize()
    )
}
}

Upvotes: 2

Views: 321

Answers (2)

Suresh Babu
Suresh Babu

Reputation: 46

Instead of using constraint layout we can add weight with fill value as false.

            Row(modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight()
                    .padding(vertical = 5.dp, horizontal = 10.dp),
                verticalAlignment = Alignment.CenterVertically) {
                Text(
                    text = description,
                    style = AITypography.current.bodyXSmall,
                    color = aiTextHeadingDark,
                    modifier = Modifier.weight(1f, fill = false)
                )
                Icon(
                    modifier = Modifier
                        .defaultMinSize(24.dp)
                        .clickable { onInformationButton() },
                    painter = painterResource(id = R.drawable.ic_information_grey),
                    contentDescription = null
                )
            }

Upvotes: 3

Bincy Baby
Bincy Baby

Reputation: 4743

After multiple attempts, I found the solution. My mistake was calling createHorizontalChain before setting the constraints. I've now moved the createHorizontalChain function to the end, after defining the Text and Image components. This is because the createHorizontalChain function should be called after the components have been defined and their constraints have been set.

ConstraintLayout(modifier = Modifier.fillMaxWidth().padding(top = 5.dp, start = 10.dp, bottom = 10.dp, end = 5.dp)) {
        val (text, image) = createRefs()

        Text(
            text = description.toString(),
            modifier = Modifier
                .constrainAs(text) {
                    start.linkTo(parent.start)
                    width = Dimension.preferredWrapContent
                }
                .wrapContentSize()
        )

        Image(
            painter = painterResource(id = R.drawable.ic_information_grey),
            contentDescription = null,
            modifier = Modifier
                .size(14.dp)
                .constrainAs(image) {
                    start.linkTo(text.end)
                    top.linkTo(text.top)
                    end.linkTo(parent.end)
                    width = Dimension.wrapContent
                }
                .wrapContentSize()
                .padding(start = 4.dp)
                .noRippleClickable {
                    onInformationButton()
                }
        )

        createHorizontalChain(text, image, chainStyle = ChainStyle.Packed(0F))
    }

Upvotes: 2

Related Questions