【问题标题】:Jetpack Compose Dynamic Spacer HeightJetpack Compose 动态垫片高度
【发布时间】:2021-09-15 21:30:10
【问题描述】:

我正在使用 Jetpack Compose 版本 1.0.2(截至今天的最新稳定版)。

我有多个LazyRows 中的Column,其中有一个Image 和两个Text

看下面的结构(简化)

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))
        }
    }
}

问题是Textshow.titleshow.info 的组合可以是多行,并且由于每个项目都是延迟加载的,因此直到它显示在屏幕上才会计算高度。结果,下一行的y 的位置跳来跳去。

要了解发生了什么,请观看此视频:Video link

如何动态计算Spacer 的高度,以使它们不会跳跃?我知道简单的解决方案只是给出一个固定的高度,但有些文本只是一个衬里,那些会有更大的差距,所以我认为这对我来说并不是很理想。

【问题讨论】:

  • 嗯,这不正是这里发生的事情吗?高度是根据文本值动态计算的。我不明白你想在这里做什么。请进一步详细说明。
  • @MARSK 是的,该行为准确地显示了它根据我的代码的预期行为方式。期望的行为是,在知道潜在的更长高度的文本组合之前,以某种方式已经知道全高,所以我可以相应地调整 Spacer 组合的高度。
  • 嗯。我是这么想的,但是当您指出如果文本很小但高度仍然很大并留有空白区域时会不好看时,我感到困惑。
  • @MARSK 对不起,我让你感到困惑。我正在寻找一些方法来根据文本可组合物的高度调整 Spacer 的高度。所以在用户看来,当前行下面的行不会跳来跳去。

标签: android android-jetpack-compose


【解决方案1】:

要计算LazyRow 的高度,您需要知道元素的所有尺寸。一个简单的解决方案是使用Box 将它们全部放在LazyRow 下,在这种情况下,大小将由它们中的最大值决定。

但是这种解决方案需要大量资源,尤其是在您有很多对象的情况下。相反,我建议您将 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
  • @SaehunSeanOh 不客气。我认为这种方法是最高效的:Compose 只需要计算一次占位符视图的大小,并且由于文本只包含换行符,因此花费的时间越少越好。而且它不会在重新组合时重新计算它,因为参数是恒定的。如果这解决了您的问题,请接受它=)
  • 绝对接受。我最终说服我们的设计团队坚持使用 1 line + ellipsize 选项,并最终删除文本 lol
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-12
  • 2022-11-25
  • 1970-01-01
  • 1970-01-01
  • 2023-02-12
  • 2021-10-25
  • 1970-01-01
相关资源
最近更新 更多