英文:
How to measure a Composable before displaying it as InlineTextContent?
问题
我想在AnnotatedString
中将Composable
用作InlineTextContent
。这需要为Placeholder
提供width
和height
。有没有一种方法可以在它被替换并显示之前预先测量我的Composable
的宽度和高度?
英文:
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?
答案1
得分: 1
我理解了你的请求。以下是你提供的代码的中文翻译:
我猜测Placeholder
要求指定大小是因为你可以传递像1.ep
这样的值给高度 - 在这种情况下,它将等于字体大小的高度,因此您可以相应地缩放内容。
但一般情况下,我使用SubcomposeLayout
- 您可以测量任何视图的大小,并根据结果对实际视图进行子组合:
@Composable
fun 测量视图大小(
要测量的视图: @Composable () -> Unit,
修饰符: Modifier = Modifier,
内容: @Composable (DpSize) -> Unit,
) {
SubcomposeLayout(modifier = 修饰符) { 约束 ->
val 测量大小 = subcompose("要测量的视图") {
要测量的视图()
}[0].measure(约束)
.let {
DpSize(
宽度 = it.width.toDp(),
高度 = it.height.toDp()
)
}
val 内容可放置 = subcompose("内容") {
内容(测量大小)
}.firstOrNull()?.measure(约束)
layout(内容可放置?.宽度 ?: 0, 内容可放置?.高度 ?: 0) {
内容可放置?.place(0, 0)
}
}
}
要与InlineTextContent
一起使用,您还需要将Dp
转换为Sp
:
@Composable
fun 视图() {
val 我的ID = "inlineContent"
val 文本 = buildAnnotatedString {
append("你好")
// 追加一个占位符字符串“[myBox]”并在其上附加一个注释“inlineContent”。
appendInlineContent(我的ID, "[myBox]")
}
val 密度 = LocalDensity.current
测量视图大小(
要测量的视图 = {
内联视图()
},
) { 测量大小 ->
val 内联内容 = mapOf(
Pair(
// 这告诉[BasicText]要用[InlineTextContent]对象中给定的组合替换占位符字符串“[myBox]”。
我的ID,
InlineTextContent(
// 占位符告诉文本布局预期大小和垂直对齐方式
with(密度) {
Placeholder(
宽度 = 测量大小.width.toSp(),
高度 = 测量大小.height.toSp(),
placeholderVerticalAlign = PlaceholderVerticalAlign.Center
)
}
) {
内联视图()
}
)
)
BasicText(
text = 文本,
inlineContent = 内联内容,
)
}
}
@Composable
private fun 内联视图() {
Box(
modifier = Modifier
.height(100.dp)
.aspectRatio(0.5f)
.background(color = Color.Red)
)
}
结果:
英文:
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:
<img src="https://i.stack.imgur.com/VvPpQ.png" width="80"></img>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论