I want to use a Composable
as InlineTextContent
in an AnnotatedString
. This requires supplying a width
and height
to the Placeholder
. Is there a way to pre-measure my Composable to know the width and height before it is swapped in and displayed?
Asked
Active
Viewed 223 times
0

coding4mobile
- 31
- 5
1 Answers
1
I guess that the reason Placeholder
asks for size that you can pass something like 1.ep
value to height - in this case it's gonna be equal to the font size height, so you can scale your content accordingly.
But generally for such purpose I'm using SubcomposeLayout
- you can measure any view size and subcompose actual view depending on the result:
@Composable
fun MeasureViewSize(
viewToMeasure: @Composable () -> Unit,
modifier: Modifier = Modifier,
content: @Composable (DpSize) -> Unit,
) {
SubcomposeLayout(modifier = modifier) { constraints ->
val measuredSize = subcompose("viewToMeasure") {
viewToMeasure()
}[0].measure(constraints)
.let {
DpSize(
width = it.width.toDp(),
height = it.height.toDp()
)
}
val contentPlaceable = subcompose("content") {
content(measuredSize)
}.firstOrNull()?.measure(constraints)
layout(contentPlaceable?.width ?: 0, contentPlaceable?.height ?: 0) {
contentPlaceable?.place(0, 0)
}
}
}
To use it with InlineTextContent
you also need to convert Dp
to Sp
:
@Composable
fun View() {
val myId = "inlineContent"
val text = buildAnnotatedString {
append("Hello")
// Append a placeholder string "[myBox]" and attach an annotation "inlineContent" on it.
appendInlineContent(myId, "[myBox]")
}
val density = LocalDensity.current
MeasureViewSize(
viewToMeasure = {
ViewToInline()
},
) { measuredSize ->
val inlineContent = mapOf(
Pair(
// This tells the [BasicText] to replace the placeholder string "[myBox]" by
// the composable given in the [InlineTextContent] object.
myId,
InlineTextContent(
// Placeholder tells text layout the expected size and vertical alignment of
// children composable.
with(density) {
Placeholder(
width = measuredSize.width.toSp(),
height = measuredSize.height.toSp(),
placeholderVerticalAlign = PlaceholderVerticalAlign.Center
)
}
) {
ViewToInline()
}
)
)
BasicText(
text = text,
inlineContent = inlineContent,
)
}
}
@Composable
private fun ViewToInline() {
Box(
modifier = Modifier
.height(100.dp)
.aspectRatio(0.5f)
.background(color = Color.Red)
)
}
Result:

Phil Dukhov
- 67,741
- 15
- 184
- 220