Jetpack Compose动态间距高度

4
我正在使用Jetpack Compose版本1.0.2(截至今天最新的稳定版)。
我有一个包含多个LazyRows的Column,其中包含一张图像和两个文本。

image

请看下面的结构(简化版)
val topicList: List<Topics>


Column {
    topicList.forEach { topic ->

        val showList: List<Show> = topic.shows

        Column {
            Text(text = topic.title)

            LazyRow {
                items(showList) { show ->
                    Column {
                        Image()
                        Text(text = show.title)
                        Text(text = show.info)
                    }
                }
            }

            Spacer(Modifier.height(32.dp))
        }
    }
}

问题在于具有show.titleshow.infoText组件可以是多行的,而且由于每个项目都是惰性加载的,直到它出现在屏幕上才计算高度。因此,下一行的y位置会跳来跳去。
为了理解发生了什么,请查看此视频:视频链接 我该如何动态计算Spacer的高度,以便它们不会跳动?我知道简单的解决方案就是给一个固定的高度,但有些文本只有一行,这将导致更大的间隙,所以我认为这并不是理想的解决方案。

这不就是正在发生的事情吗?高度是根据文本值动态计算的。我不明白你想要什么。请进一步阐述。 - Richard Onslow Roper
@MARSK 是的,该行为正如我的代码所预期的那样。期望的行为是在可能更长的高度文本组合之前就已经知道了完整的高度,以便我可以相应地调整 Spacer 组合的高度。 - Saehun Sean Oh
嗯,我也是这么想的,但当你指出如果文本很小但高度仍然很大会留下空白时,我有些困惑了。 - Richard Onslow Roper
@MARSK 抱歉让你感到困惑。我正在寻找一些方法来根据 Text Composables 的高度调整 Spacer 的高度,以便于用户的视觉体验,使得当前行下面的行不会跳动。 - Saehun Sean Oh
1个回答

4
为了计算LazyRow的高度,您需要知道所有元素的尺寸。一个直接的解决方案是将它们全部放在LazyRow下面,使用Box,在这种情况下,大小将由它们中最大的确定。
但是这种解决方案需要大量资源,特别是如果您有很多对象。相反,我建议您通过限制infotitle的行数来计算最大尺寸,比如说限制为2行,并计算出两个文本都具有最大行数的最大尺寸。
@Composable
fun TopicList(topicList: List<Topics>) {
    Column {
        topicList.forEach { topic ->
            val showList = topic.shows
            Column {
                Text(text = topic.title)
                Box {
                    ShowCell(
                        placeholderShow,
                        modifier = Modifier.alpha(0f)
                    )
                    LazyRow(
                        horizontalArrangement = Arrangement.spacedBy(10.dp)
                    ) {
                        items(showList) { show ->
                            ShowCell(show)
                        }
                    }
                }
            }
        }
    }
}

@Composable
fun ShowCell(
    show: Show,
    modifier: Modifier = Modifier
) {
    Column(
        modifier
            .width(200.dp)
    ) {
        Image(
            painter = rememberImagePainter(show.image),
            contentDescription = "...",
            contentScale = ContentScale.Crop,
            modifier = Modifier.aspectRatio(2f)
        )
        Text(
            show.title,
            fontSize = 20.sp,
            maxLines = titleMaxLines,
            overflow = TextOverflow.Ellipsis,
        )
        Text(
            text = show.info,
            maxLines = infoMaxLines,
            overflow = TextOverflow.Ellipsis,
        )
    }
}

private const val titleMaxLines = 2
private const val infoMaxLines = 2
private val placeholderShow = Show(
    image = "",
    title = List(titleMaxLines) { '\n' }.joinToString(separator = ""),
    info = List(titleMaxLines) { '\n' }.joinToString(separator = ""),
)

结果:


这似乎是最可行的解决方案。虽然不太理想,但它仍然可以通过不使用普通的Row并放弃延迟加载来节省一些资源(特别是当需求无法改变时)。非常感谢!没想到可以利用某种类型的占位符 :)。除了使用资源外,唯一的缺点是如果所有展示都只有一行标题和信息的情况下,它将只是看起来有更大的边距 lol - Saehun Sean Oh
1
@SaehunSeanOh 不用客气。我认为这种方法是最高效的:Compose只需要计算占位视图的大小一次,由于文本只包含换行符,因此需要尽可能少的时间。此外,它不会在重新组合时重新计算,因为参数是常数。如果这解决了你的问题,请接受它=) - Phil Dukhov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接