反转行中项目的顺序

H4k*_*4kt 4 android kotlin android-jetpack-compose

我有一个代表消息的可组合组件。每条消息都可以是传入或传出,具体取决于我想要反转消息组件中的所有项目。

我发现的唯一方法是强制 RTL 布局,但这也会导致文本被反转。 例子

还有其他办法解决这个问题吗?

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))

}
Run Code Online (Sandbox Code Playgroud)

H4k*_*4kt 6

因此,我想出了一种解决方案,可以创建一个自定义水平排列,它使用现有End排列中的代码。

HorizontalArrangementExts.kt

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

val Arrangement.Reverse: Arrangement.Horizontal
    get() = ReverseArrangement

object ReverseArrangement : Arrangement.Horizontal {

    override fun Density.arrange(
        totalSize: Int,
        sizes: IntArray,
        layoutDirection: LayoutDirection,
        outPositions: IntArray
    ) = if (layoutDirection == LayoutDirection.Ltr) {
        placeRightOrBottom(totalSize, sizes, outPositions, reverseInput = true)
    } else {
        placeLeftOrTop(sizes, outPositions, reverseInput = false)
    }

    // Had to copy function from sources because it is marked internal
    private fun placeRightOrBottom(
        totalSize: Int,
        size: IntArray,
        outPosition: IntArray,
        reverseInput: Boolean
    ) {
        val consumedSize = size.fold(0) { a, b -> a + b }
        var current = totalSize - consumedSize
        size.forEachIndexed(reverseInput) { index, it ->
            outPosition[index] = current
            current += it
        }
    }

    // Had to copy function from sources because it is marked internal
    private fun placeLeftOrTop(size: IntArray, outPosition: IntArray, reverseInput: Boolean) {
        var current = 0
        size.forEachIndexed(reverseInput) { index, it ->
            outPosition[index] = current
            current += it
        }
    }

    // Had to copy function from sources because it is marked private
    private inline fun IntArray.forEachIndexed(reversed: Boolean, action: (Int, Int) -> Unit) {
        if (!reversed) {
            forEachIndexed(action)
        } else {
            for (i in (size - 1) downTo 0) {
                action(i, get(i))
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)