https://kotlinlang.org logo
#compose
Title
# compose
k

kotlinforandroid

06/19/2022, 11:27 AM
I have some problems with
InlineTextContent
. I am trying to add readings annotations to existing text. However, if I simply add the exact same text using a placeholder, the text gets added written vertically for some reason. I think the reason is that the placeholder width isn't exactly the same as the width the original text would have needed. But the way I did it I do not see the issue. (thread)
Copy code
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.*
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.em

data class TextData(
    val text: String,
    val reading: String? = null,
)

@Composable
fun TextWithReading(
    textData: List<TextData>,
) {
    val (text, inlineContent) = remember(textData) {
        calculateAnnotatedString(textData)
    }
    Text(text = text, inlineContent = inlineContent)
}

private fun calculateAnnotatedString(textData: List<TextData>): Pair<AnnotatedString, Map<String, InlineTextContent>> {
    val inlineContent = mutableMapOf<String, InlineTextContent>()

    return buildAnnotatedString {
        for (elem in textData) {
            val text = elem.text
            val reading = elem.reading

            // If there is not reading available, simply add the text and move to the next element.
            if (reading == null) {
                append(text)
                continue
            }

            appendInlineContent(text, text)
            inlineContent[text] = InlineTextContent(
                placeholder = Placeholder(
                    width = text.length.em,
                    height = 2.em,
                    placeholderVerticalAlign = PlaceholderVerticalAlign.Bottom,
                ),
                children = {
                    val readingFontSize = LocalTextStyle.current.fontSize / 2

                    Column(
                        modifier = Modifier.fillMaxSize(),
                        horizontalAlignment = Alignment.CenterHorizontally,
                        verticalArrangement = Arrangement.Bottom,
                    ) {
                        Text(
                            text = reading,
                            style = TextStyle.Default.copy(fontSize = readingFontSize)
                        )
                        Text(text = text)
                    }
                }
            )
        }
    } to inlineContent
}

@Preview
@Composable
internal fun PreviewTextWithReading() {
    val textData = listOf(
        TextData(text = "このルールを"),
        TextData(text = "守", reading = "まも"),
        TextData(text = "るらない"),
        TextData(text = "人", reading = "ひと"),
        TextData(text = "は"),
        TextData(text = "旅行", reading = "りょこう"),
        TextData(text = "ができなくなることもあります。"),
    )

    MaterialTheme {
        TextWithReading(textData = textData)
    }
}
For some reason the string
旅行
is written as marked with the red box even though there is still space left on the right of the first character.
There is a thin segment right to the text's box. I think it's the missing width but I am not sure why this is happening.
z

Zach Klippenstein (he/him) [MOD]

06/22/2022, 8:06 PM
Please file a bug, and make sure to include this code and your screenshots
92 Views