You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose预览中显示Coil的SubcomposeAsyncImage?

如何在Compose预览中显示Coil的SubcomposeAsyncImage加载的图片?

我编写了一个简单的图片加载组件,同时尝试了带占位符的AsyncImage和支持加载指示器的SubcomposeAsyncImage(更倾向于后者)。但遇到了问题:图片无法在Compose预览中显示,而带占位符的AsyncImage能正常预览。我想知道如何让SubcomposeAsyncImage实现预览效果,或者至少能在预览中传入本地URL来显示图片。

组件代码

@Composable
fun LoadableImage(
    url: String?,
    cornerRadius: Dp = 10.dp,
    description: String? = ""
) {
    SubcomposeAsyncImage(
        model = ImageRequest.Builder(LocalContext.current)
            .data(url)
            .crossfade(true)
            .build(),
        loading = {
            CircularProgressIndicator()
        },
        contentDescription = description,
        contentScale = ContentScale.Crop,
        modifier = Modifier.clip(RoundedCornerShape(cornerRadius))
    )
    /*
    AsyncImage(
        model = ImageRequest.Builder(LocalContext.current)
            .data(url)
            .crossfade(true)
            .build(),
        placeholder = painterResource(id = R.drawable.mock_game_card),
        contentDescription = "",
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .clip(CircleShape)
            .background(Color.Red)
    )
     */
}

当前预览代码

@Preview(
    showBackground = true
)
@Composable
fun PreviewLoadableImage() {
    MyTheme {
        LoadableImage(
            url = Game.defaultGame.thumbnail
        )
    }
}

解决方案

1. 预览时直接传入本地资源URI

Compose预览环境无法发起网络请求,因此可以在预览函数中把URL替换为本地图片的资源URI,让Coil加载本地资源:

@Preview(showBackground = true)
@Composable
fun PreviewLoadableImage() {
    MyTheme {
        val context = LocalContext.current
        // 替换为你的本地图片资源ID
        val localImageUri = Uri.parse("android.resource://${context.packageName}/${R.drawable.mock_game_card}")
        LoadableImage(
            url = localImageUri.toString()
        )
    }
}

2. 组件内适配预览环境,自动切换数据源

通过LocalInspectionMode.current判断是否处于预览环境,自动切换为本地占位资源,同时在预览时隐藏加载指示器:

@Composable
fun LoadableImage(
    url: String?,
    cornerRadius: Dp = 10.dp,
    description: String? = "",
    // 新增预览专用占位资源参数
    previewImageResId: Int? = null
) {
    val isPreview = LocalInspectionMode.current
    // 预览环境且有指定占位资源时,使用本地Drawable作为数据源
    val imageData = if (isPreview && previewImageResId != null) {
        ContextCompat.getDrawable(LocalContext.current, previewImageResId)
    } else {
        url
    }

    SubcomposeAsyncImage(
        model = ImageRequest.Builder(LocalContext.current)
            .data(imageData)
            .crossfade(true)
            .allowHardware(false) // 预览中禁用硬件加速,避免渲染问题
            .build(),
        loading = {
            // 预览环境不显示加载指示器
            if (!isPreview) {
                CircularProgressIndicator()
            }
        },
        contentDescription = description,
        contentScale = ContentScale.Crop,
        modifier = Modifier.clip(RoundedCornerShape(cornerRadius))
    )
}

对应的预览函数调用:

@Preview(showBackground = true)
@Composable
fun PreviewLoadableImage() {
    MyTheme {
        LoadableImage(
            url = Game.defaultGame.thumbnail,
            previewImageResId = R.drawable.mock_game_card
        )
    }
}

内容的提问来源于stack exchange,提问作者ssantos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 16:28:09