kotlinforandroid
04/14/2025, 7:21 AMruby
tag. I am looking for an alternative solution for Compose. There are some edgecases that I have problems implementing. I will give a short overview and then my current code inside the thread.kotlinforandroid
04/14/2025, 7:29 AMColumn
that holds two Text
components stacked vertically. That way I can do mono and jukogo variants, but it requires me to manually parse a sentence into words.
@Composable
fun TextWithReading(
textContent: List<TextData>,
showReadings: Boolean = false,
) {
val (text, inlineContent) = remember(textContent) {
calculateAnnotatedString(textContent = textContent, showReadings = showReadings)
}
Text(text = text, inlineContent = inlineContent)
}
fun calculateAnnotatedString(textContent: List<TextData>, showReadings: Boolean):
Pair<AnnotatedString, Map<String, InlineTextContent>> {
val inlineContent = mutableMapOf<String, InlineTextContent>()
return buildAnnotatedString {
for (elem in textContent) {
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
}
// Words larger than one character/kanji need a small amount of additional space in their
// x-dimension.
val width = (text.length.toDouble() + (text.length - 1) * 0.05).em
appendInlineContent(text, text)
inlineContent[text] = InlineTextContent(
// TODO: find out why height and width need magic numbers.
placeholder = Placeholder(
width = width,
height = 1.97.em,
placeholderVerticalAlign = PlaceholderVerticalAlign.Bottom,
),
children = {
val readingFontSize = LocalTextStyle.current.fontSize / 2
val boxHeight = with(LocalDensity.current) { readingFontSize.toDp() }
Column(
modifier = Modifier.fillMaxHeight(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Bottom,
) {
Box(modifier = Modifier.requiredHeight(boxHeight + 3.dp)) {
if (showReadings) {
Text(
modifier = Modifier.wrapContentWidth(unbounded = true),
text = reading,
style = TextStyle.Default.copy(fontSize = readingFontSize)
)
}
}
Text(text = text)
}
}
)
}
} to inlineContent
}
@Preview
@Composable
internal fun PreviewTextWithReading() {
val textContent = listOf(
TextData(text = "このルールを"),
TextData(text = "守", reading = "まも"),
TextData(text = "るらない"),
TextData(text = "人", reading = "ひと"),
TextData(text = "は"),
TextData(text = "旅行", reading = "りょこう"),
TextData(text = "ができなくなることもあります。"),
)
MaterialTheme {
TextWithReading(textContent = textContent, showReadings = true)
}
}
I would really like to take advantage of Compose's new Text splitting API: https://developer.android.com/develop/ui/compose/text/style-paragraph#cjk-considerations
Compose already knows the rules for splitting text into usable chunks. Is there any way to hook into this?
I don't see how I can make this work without access to the text layout engine. Given that, I assume I have to use SubcomposeLayout? Is it possible to create the mono and jukogo variants without subcompose?