LazyColumn 上的图像可组合问题

问题描述 投票:0回答:1

简介:

我正在 Jetpack Compose 中构建一个简单的应用程序。在应用程序的“主页”部分中,我显示了一个项目列表。没什么好看的。 我使用

LazyColumn
内的自定义卡来完成此操作。

问题:

应用程序加载时,将显示列表,然后首次显示项目。然后我向下滚动,所有项目都按预期显示在

custom card
中。
当我向上滚动然后再次向下滚动时,问题就会出现,基本上是重新组合/重新渲染项目。 然后自定义卡的
image
会完全忽略它的
contentScale
和它的
modifier
并破坏布局。非常奇怪的事情。

我尝试过什么:

  • 我首先尝试用
    custom card
    columns
    构建
    rows

  • 然后我用
    ConstraintLayout
    构建了它。
  • 尝试
    remember
    modidier

我想实现什么目标:

  • A
    custom card
    ,其中具有定义的
    height
    (180.dp) 和
    fillMaxWidth
  • image
    放置在
    start
    custom card
    上,其高度和宽度应固定(例如宽度:124.dp,高度:180.dp)。

自定义卡代码:

@Composable
fun ProductCard(
    data: ProductDisplayData,
    onClick: (ProductDisplayData) -> Unit = {}
) {

    val constraints = ConstraintSet {
        val imageSection = createRefFor("imageSection")
        val textSection = createRefFor("textSection")
        constrain(imageSection) {
            top.linkTo(parent.top)
            start.linkTo(parent.start)
            end.linkTo(textSection.start)
            width = Dimension.value(128.dp)
            height = Dimension.value(180.dp)
        }
        constrain(textSection) {
            top.linkTo(parent.top)
            start.linkTo(imageSection.end)
            bottom.linkTo(parent.bottom)
            end.linkTo(parent.end)
            width = Dimension.fillToConstraints
            height = Dimension.fillToConstraints
        }
    }

    ConstraintLayout(constraints, modifier = Modifier
        .fillMaxWidth()
        .clip(RoundedCornerShape(8.dp))
        .padding(vertical = 8.dp)
        .clickable { onClick(data) }
    ) {
        if (data.image != null) {
            Box(
                modifier = Modifier
                    .layoutId("imageSection")
                    .height(180.dp)
                    .width(128.dp)
                    .clip(RoundedCornerShape(8.dp))
                    .clipToBounds()
            ) {
                Image(
                    bitmap = data.image.asImageBitmap(),
                    contentDescription = "Product Image",
                    modifier = Modifier
                        .fillMaxSize()
                )
            }

        }
        Column(
            modifier = Modifier
                .layoutId("textSection")
                .fillMaxWidth()
                .padding(8.dp),
            verticalArrangement = Arrangement.spacedBy(4.dp)
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    text = data.name,
                    fontWeight = FontWeight.Bold,
                    fontSize = 18.sp,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                    modifier = Modifier.weight(1f)
                )
                Text(text = "${data.price}$" )
            }
            Text(text = data.brand, fontWeight = FontWeight.Bold, fontSize = 14.sp)
            Text(text = data.size, modifier = Modifier, fontWeight = FontWeight.SemiBold, fontSize = 12.sp, fontStyle = FontStyle.Italic)
            Text(text = data.category, fontWeight = FontWeight.SemiBold, fontSize = 12.sp)
            LazyRow {
                items(data.tags) { tag ->
                    Chip(
                        name = tag,
                        isSelected = false,
                        onSelectionChanged = {}
                    )
                }
            }
            Text(
                text = data.description,
                maxLines = 2,
                overflow = TextOverflow.Ellipsis,
                fontWeight = FontWeight.Light,
                fontSize = 12.sp
            )
        }
    }
}

正在发生的事情的图像和图形解释:

  • 这是该项目第一次显示在 LazyColumn 中 This is the first time the item is shown in the LazyColumn

  • 这是第二次了,基本上又上下滚动了一遍。在这种情况下,contentScale 已经完全消失了。 This is the second time, basically scrolled up and down again. In this case the contentScale has completely gone away.

  • 还要查看第一次显示该项目时图像的角半径 (.clip)。 Also look at the corner radius (.clip) of the image at the first time the item is shown.

  • 第二次显示该项目时,圆角半径 (.clip) 消失了,因此基本上修改器也消失了。 The corner radius (.clip) is gone on the second time the item is shown, so basically also the modifiers are gone.



MRE:

image
的唯一特点是它作为
base64
字符串出现在响应中,并从中转换为
bitmap
。这就是为什么我使用
Image
而不是
coil (AsyncImage)
来显示图像。 由于长度原因,我无法为此 MRE 放置 base64 字符串。
为了测试它,请将图像转换为 Base64 字符串。
ProductCard
代码已发布在上面。

data class ProductDisplayData(
    val id: Int,
    val name: String,
    val description: String,
    val size: String,
    val ownerName: String,
    val ownerID: Int,
    val price: String,
    val category: String,
    val brand: String,
    val tags: List<String>,
    val image: Bitmap?
)

val products = listOf(
   ProductDisplayData(
        id = 0,
        name = "Polo",
        description = "Nice slim fit polo shirt, perfect for casual wear, available in multiple colors",
        size = "Small",
        price = "120",
        image = bitmapFromBase64String,
        brand = "Boss",
        category = "Shirts",
        tags = listOf("Shirts", "Boss", "Slim fit", "Casual", "Polo", "Small"),
        ownerName = "John Doe",
        ownerID = 0
    )
    //repeat it until the list overflows...

)
@Composable
fun HomeScreen() {
   LazyColumn(
            modifier = Modifier.fillMaxWidth(),
            contentPadding = PaddingValues(vertical = 16.dp),

            ) {
            items(products) { product ->
                ProductCard(
                    data = product
                ) { productSelected ->
                    // do action... irrelevant for this issue.
                }
            }
        }
}

非常有趣的细节是,如果我使用

coil (AsyncImage)
应用硬编码的 url 进行测试,则不会发生此问题并且它可以正常工作。我是不是遇到了
androidx.compose.foundation.Image
Bug?

android kotlin android-jetpack-compose
1个回答
0
投票

我花了两天时间才解决这个极其奇怪的问题。我使用

Coil
函数
rememberAsyncImagePainter
修复了它。我不能 100% 确定这是否是更合适的方法,但它应该有效。
我很乐意阅读想法:),无论如何,感谢@Leviathan 您的时间。

这就是

Image
代码的样子:

Image(
                contentScale = ContentScale.Crop,
                painter = rememberAsyncImagePainter(it),
                contentDescription = "Product Image",
                modifier = Modifier
                    .clipToBounds()
                    .height(180.dp)
                    .width(128.dp)
                    .layoutId("imageSection")
                    .clip(RoundedCornerShape(8.dp))
            )
© www.soinside.com 2019 - 2024. All rights reserved.