Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reverse order of items in a Row

I have a composable component that represent a message. Each message can either be incoming or outgoing, depending on that I would like to reverse all items in my message component.

The only way I found is to force a RTL layout, however it leads to text being reversed too. Example

Is there any other way around this?

MessageView.kt

@Composable
fun MessageView(
    message: Message
) = Row(
    modifier = Modifier
        .fillMaxWidth()
        .wrapContentHeight(),
    verticalAlignment = Alignment.Bottom
) {

    val (isIncoming) = message

    val direction = if (isIncoming) {
        LayoutDirection.Ltr
    } else {
        LayoutDirection.Rtl
    }

    CompositionLocalProvider(
        LocalLayoutDirection provides direction
    ) {
        MessageViewContent(message)
    }

}

@Composable
private fun MessageViewContent(
    message: Message
) = Row(
    modifier = Modifier
        .fillMaxWidth()
        .wrapContentHeight(),
    verticalAlignment = Alignment.Bottom
) {

    val (isIncoming, text, at) = message

    val background: Color
    val textColor: Color
    val timeColor: Color
    val alignment: Alignment.Horizontal
    val textAlignment: TextAlign

    if (isIncoming) {
        background = Color(0xFFEFEFEF)
        textColor = Color(0xFF000000)
        timeColor = Color(0xFF929292)
        alignment = Alignment.End
        textAlignment = TextAlign.Start
    } else {
        background = Color(0xFFE0727F)
        textColor = Color(0xFFFEFEFE)
        timeColor = Color(0xB3FEFEFE)
        alignment = Alignment.Start
        textAlignment = TextAlign.End
    }

    Image(
        modifier = Modifier
            .size(40.dp)
            .clip(CircleShape),
        painter = painterResource(R.drawable.ic_launcher_background),
        contentDescription = null
    )

    Spacer(modifier = Modifier.width(12.dp))

    Column(
        modifier = Modifier
            .weight(1F, fill = false)
            .wrapContentWidth()
            .background(
                color = background,
                shape = RoundedCornerShape(8.dp)
            )
            .padding(4.dp),
        horizontalAlignment = alignment
    ) {

        Text(
            modifier = Modifier.padding(6.dp),
            style = TextStyle(
                fontSize = 16.sp,
                color = textColor
            ),
            text = text
        )

        Text(
            style = TextStyle(
                fontSize = 10.sp,
                color = timeColor,
                textAlign = textAlignment
            ),
            text = "${at.hour}:${at.minute}",
        )

    }

    Spacer(modifier = Modifier.width(60.dp))

}
like image 636
H4kt Avatar asked Sep 17 '25 13:09

H4kt


1 Answers

So, I figured out a solution One can create a custom Horizontal Arrangement which uses code from already existing arrangements.

To use it, the containing Row should span the width of the surface it's displayed on, and the items will simply be stacked the inverse side if the message is from the sender side.

ConversationSide.kt

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection

private sealed interface ConversationSide : Arrangement.Horizontal {


    data object Sender : ConversationSide {

        override fun Density.arrange(
            totalSize: Int,
            sizes: IntArray,
            layoutDirection: LayoutDirection,
            outPositions: IntArray
        ) {
            with(Arrangement.Start) {
                arrange(
                    totalSize = totalSize,
                    sizes = sizes,
                    layoutDirection = when (layoutDirection) {
                        LayoutDirection.Ltr -> LayoutDirection.Rtl
                        LayoutDirection.Rtl -> LayoutDirection.Ltr
                    },
                    outPositions = outPositions
                )
            }
        }
    }

    data object Receiver :
        ConversationSide,
        Arrangement.Horizontal by Arrangement.Start 
}

Usage:

@Composable
fun MessageView(
    message: Message
) = Row(
    modifier = Modifier
        .fillMaxWidth()
        .wrapContentHeight(),
    verticalAlignment = Alignment.Bottom,
    horizontalArrangement = when {
        message.isIncoming -> Side.Receiver
        else -> Side.Sender
    }
) {

    ...

}
like image 85
H4kt Avatar answered Sep 19 '25 04:09

H4kt