最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - Why doesn't the Text Composable fit the size that the text occupies? - Stack Overflow

programmeradmin3浏览0评论

I have this code, in MessageItem is the Surface and also inside that Surface is the Text.

I tried with .wrapContentSize() but it didn't work

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ChatScreen(
    chatId: String?,
    onBack: () -> Unit
) {
    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text(
                        text = "Chat with Alice"
                    )
                }
            )
        },
        bottomBar = {
            SendMessageBox()
        }
    ) { innerPadding ->
        ListOfMessages(modifier = Modifier.padding(innerPadding))
    }
}
@Composable
fun ListOfMessages(modifier: Modifier = Modifier) {

    LazyColumn(
        modifier = modifier.fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(getFakeMessages()) { message ->
            MessageItem(message)
        }
    }
}
@Composable
fun MessageItem(message: Message) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .then(if (message.isMine) Modifier.padding(start = 48.dp) else Modifier),
        horizontalArrangement = if (message.isMine) Arrangement.End else Arrangement.Start
    ) {
        if (!message.isMine) {
            Avatar(
                imageUrl = message.senderAvatar,
                size = 40.dp,
                contentDescription = "${message.senderName}'s avatar"
            )
            Spacer(modifier = Modifier.width(8.dp))
        }
        Column {
            if (message.isMine) {
                Spacer(modifier = Modifier.height(8.dp))
            } else {
                Text(
                    text = message.senderName,
                    fontWeight = FontWeight.Bold
                )
            }
            when (val content = message.messageContent) {
                is MessageContent.TextMessage -> {
                    Surface(
                        shape = RoundedCornerShape(8.dp),
                        color = if (message.isMine) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary
                    ) {
                        Text(
                            text = content.message,
                            modifier = Modifier.padding(8.dp),
                            color = if (message.isMine) MaterialTheme.colorScheme.onPrimary else Color.White
                        )
                    }
                }

                is MessageContent.ImageMessage -> {
                    AsyncImage(
                        model = content.imageUrl,
                        contentDescription = content.contentDescription,
                        modifier = Modifier
                            .size(40.dp)
                            .clip(CircleShape),
                        contentScale = ContentScale.Crop
                    )
                }
            }
            Text(
                text = message.timestamp,
                fontSize = 12.sp
            )
        }
    }
}

Any idea what I'm doing wrong and why the Surface doesn't fit the size of the text?

I have this code, in MessageItem is the Surface and also inside that Surface is the Text.

I tried with .wrapContentSize() but it didn't work

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ChatScreen(
    chatId: String?,
    onBack: () -> Unit
) {
    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text(
                        text = "Chat with Alice"
                    )
                }
            )
        },
        bottomBar = {
            SendMessageBox()
        }
    ) { innerPadding ->
        ListOfMessages(modifier = Modifier.padding(innerPadding))
    }
}
@Composable
fun ListOfMessages(modifier: Modifier = Modifier) {

    LazyColumn(
        modifier = modifier.fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(getFakeMessages()) { message ->
            MessageItem(message)
        }
    }
}
@Composable
fun MessageItem(message: Message) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .then(if (message.isMine) Modifier.padding(start = 48.dp) else Modifier),
        horizontalArrangement = if (message.isMine) Arrangement.End else Arrangement.Start
    ) {
        if (!message.isMine) {
            Avatar(
                imageUrl = message.senderAvatar,
                size = 40.dp,
                contentDescription = "${message.senderName}'s avatar"
            )
            Spacer(modifier = Modifier.width(8.dp))
        }
        Column {
            if (message.isMine) {
                Spacer(modifier = Modifier.height(8.dp))
            } else {
                Text(
                    text = message.senderName,
                    fontWeight = FontWeight.Bold
                )
            }
            when (val content = message.messageContent) {
                is MessageContent.TextMessage -> {
                    Surface(
                        shape = RoundedCornerShape(8.dp),
                        color = if (message.isMine) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary
                    ) {
                        Text(
                            text = content.message,
                            modifier = Modifier.padding(8.dp),
                            color = if (message.isMine) MaterialTheme.colorScheme.onPrimary else Color.White
                        )
                    }
                }

                is MessageContent.ImageMessage -> {
                    AsyncImage(
                        model = content.imageUrl,
                        contentDescription = content.contentDescription,
                        modifier = Modifier
                            .size(40.dp)
                            .clip(CircleShape),
                        contentScale = ContentScale.Crop
                    )
                }
            }
            Text(
                text = message.timestamp,
                fontSize = 12.sp
            )
        }
    }
}

Any idea what I'm doing wrong and why the Surface doesn't fit the size of the text?

Share Improve this question asked Nov 28, 2024 at 9:56 DadkyDadky 251 silver badge3 bronze badges 1
  • Welcome to stackoverflow! If you found an answer useful, you can mark it as accepted answer by clicking the checkmark button at the left side of an answer. Thank you! – BenjyTec Commented Nov 28, 2024 at 10:14
Add a comment  | 

1 Answer 1

Reset to default 2

This is a bug / not supported feature that is present since the beginnings of Jetpack Compose, as described in Issue #206039942 on the Google Issue Tracker.

There is a suggested workaround that you can use. The Text Composable has a onTextLayout callback which returns a TextLayoutResult. The TextLayoutResult holds information about the coordinates of each individual line displayed in the Text Composable.

By then applying a layout Modifier, you can alter the size of the Text Composable to match the measured width of the longest line inside of the Text Composable.

You can create a WrappingText Composable like this:

@Composable
fun WrappingText(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    lineHeight: TextUnit = TextUnit.Unspecified,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
    minLines: Int = 1,
    style: TextStyle = LocalTextStyle.current

) {
    var textLayoutResult: TextLayoutResult? by remember { mutableStateOf(null) }
    Text(
        text = text,
        modifier = modifier
            .layout { measurable, constraints ->
                val placeable = measurable.measure(constraints)
                val newTextLayoutResult = textLayoutResult!!

                if (newTextLayoutResult.lineCount == 0) {
                    // Default behavior if there is no text
                    layout(placeable.width, placeable.height) {
                        placeable.placeRelative(0, 0)
                    }
                } else {
                    // get coordinate of line which goes the furthest to the left
                    val minX = (0 until newTextLayoutResult.lineCount).minOf(newTextLayoutResult::getLineLeft)
                    // get coordinate of line which goes the furthest to the right
                    val maxX = (0 until newTextLayoutResult.lineCount).maxOf(newTextLayoutResult::getLineRight)
                    // set width to match longest line
                    layout(ceil(maxX - minX).toInt(), placeable.height) {
                        placeable.placeRelative(-floor(minX).toInt(), 0)
                    }
                }
            },
        onTextLayout = {
            textLayoutResult = it
        },
        color = color,
        fontSize = fontSize,
        fontStyle = fontStyle,
        fontWeight = fontWeight,
        fontFamily = fontFamily,
        letterSpacing = letterSpacing,
        textDecoration = textDecoration,
        textAlign = textAlign,
        lineHeight = lineHeight,
        overflow = overflow,
        softWrap = softWrap,
        maxLines = maxLines,
        minLines = minLines,
        style = style
    )
}

Then, use it in your MessageItem Composable like this:

Surface(
    modifier = Modifier.wrapContentSize(),
    shape = RoundedCornerShape(8.dp),
    color = MaterialTheme.colorScheme.primary
) {
    WrappingText(
        modifier = Modifier
            .padding(8.dp)
            .wrapContentSize(),
        text = "Are you going to that Kotlin conference to Colorado next week, my dear friend?",
        color = MaterialTheme.colorScheme.onPrimary,
        textAlign = TextAlign.End
    )
}

Output:

发布评论

评论列表(0)

  1. 暂无评论