Coil rememberAsyncImagePainter 状态未更新。

7

我使用 CoilCompose

我正在尝试在图片加载时制作闪烁动画。
所有的例子都使用 ImagePainterImagePainter.State,它们可以正常工作,但现在被标记为“弃用”。
这就是为什么我选择了 AsyncImagePainter。没有状态检查它可以完美地工作,但添加状态检查后我得到了一个无限的闪烁动画
我还尝试在 AsyncImagePainter 的 onSuccess 方法中使用 mutableState 改变 load state 变量,但动画仍然是无限的

@Composable
fun FoodItem(food: Fun) {
    Column (
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.Start,
        verticalArrangement = Arrangement.Top
    ) {
        val painter = rememberAsyncImagePainter(food.image.sm)
        if (painter.state is AsyncImagePainter.State.Loading) {
            AnimatedShimmer { ShimmerFoodItem(brush = it) }
        } else {
            Image(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(104.dp)
                    .clip(RoundedCornerShape(size = 8.dp)),
                painter = painter,
                contentScale = ContentScale.Crop,
                contentDescription = "Food photo"
            )
            Text(
                modifier = Modifier.padding(top = 4.dp),
                text = food.title,
                fontSize = MaterialTheme.typography.body1.fontSize,
                overflow = TextOverflow.Ellipsis,
                maxLines = 1,
                fontWeight = FontWeight.Bold
            )
            Text(
                text = food.subtitle,
                fontSize = MaterialTheme.typography.subtitle2.fontSize,
                overflow = TextOverflow.Ellipsis,
                maxLines = 2,
                fontWeight = FontWeight.Normal
            )
        }
    }
}
3个回答

8

您需要提供大小,使用

model = ImageRequest.Builder(LocalContext.current)
    .data(overlayImage)
    .size(coil.size.Size.ORIGINAL) // Set the target size to load the image at.
    .build()

如果您注释掉size这一行,您会发现它会停留在加载状态。此外,您可以提供任何您想要加载的图像尺寸,例如1280x720,使用.size(coil.size.Size(1280, 720))

@Composable
private fun CoilSample() {
    val overlayImage =
        "https://images6.alphacoders.com/488/thumb-1920-488158.jpg"

    val painter = rememberAsyncImagePainter(
        model = ImageRequest.Builder(LocalContext.current)
            .data(overlayImage)
            .size(coil.size.Size.ORIGINAL) // Set the target size to load the image at.
            .build()
    )

    Column(modifier = Modifier.fillMaxSize()) {

        Text("state:${painter.state}")

        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            if (painter.state is AsyncImagePainter.State.Loading) {
                CircularProgressIndicator()
            } else {
                Image(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(104.dp)
                        .clip(RoundedCornerShape(size = 8.dp)),
                    painter = painter,
                    contentScale = ContentScale.Crop,
                    contentDescription = "photo"
                )
            }
        }
    }
}

如果您需要从 Coil 的 painter 获取 BitmapImageBitmap,您也可以查看这个答案。

在 Composable 中使用 Bitmap 前获取


0

这是我如何做到的,包括在状态出错时显示一个占位图标,例如,如果图像 URL 无效。Painter 立即提供给 Composable,但我添加了另一个状态 showImage,它的初始值为 true,并且可以根据 ImageLoadingState 的变化而改变。您可以将整个代码放在一个接受 URL 参数的函数中,并根据 ShowImage/Loading/Error 的状态只显示一个 Composable:

val modifier = Modifier
            .clip(RoundedCornerShape(CornerSize(10.dp)))
            .padding(4.dp)

val url = "your_image_url_or_not"

val imagePainter = rememberAsyncImagePainter(
    model = ImageRequest.Builder(LocalContext.current)
      .data(url)
      .crossfade(true)
      .build(),
  )

val showImage = remember {
    mutableStateOf(true)
  }
 if (showImage.value) {
    Image(
      painter = imagePainter,
      contentDescription = description,
      contentScale = ContentScale.Fit,
      modifier = modifier.padding(3.dp),
    )
  }

  if (imagePainter.state is AsyncImagePainter.State.Loading) {
    showImage.value = false
    CircularProgressIndicator(
      modifier = modifier,
      strokeWidth = 2.dp,
      color = MaterialTheme.colors.primaryVariant
    )
  } else if (imagePainter.state is AsyncImagePainter.State.Error) {
    showImage.value = false
    Icon(
      imageVector = Icons.Default.Person,
      contentDescription = description,
      modifier = modifier,
      tint = MaterialTheme.colors.primary
    )
  } else {
    showImage.value = true
  }

-1

看起来需要立即将 painter 提供到一个 Image 组合中,以便其状态可以更改。我尝试实现您的用例,并记录了 painter.state,但除非立即在 Image 上提供它,否则它不会得到更新,所以最终我得到了这个。

// random public image
val painter = rememberAsyncImagePainter(
    model = ImageRequest.Builder(LocalContext.current)
        .data("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQUJ0jVyT2UJwn_Ln5s4yd17MtwLlgzm8-WTGKExqZg&s")
        .build()
)

Box {

    Image(
        modifier = Modifier.size(150.dp),
        painter = painter,
        contentDescription = ""
    )

    runBlocking {
        delay(500)
    }

    if (painter.state is AsyncImagePainter.State.Loading) {
        Box(
            modifier = Modifier
                .size(150.dp)
                .background(Color.Red)
        )
    }
}

基于 Coil 示例
请不要介意 runbBlocking 和红色的 Box,我只是把它们放在上面模拟 Image 上的某些东西(闪烁),延迟显示实际的 Image(获取)。希望这可以帮到您。

1
谢谢,这帮助我解决了问题。但现在图片加载得太快了,物品的闪烁甚至没有时间绘制 :) - qveex

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