4. Image 组件与资源加载
在 Jetpack Compose 中,Image 组件是展示图片的核心控件,它支持本地资源、网络图片以及自定义加载策略。本章聚焦于如何通过 Image 加载本地图片(painterResource)和网络图片(Coil / Glide),并控制占位图(placeholder)、缩放模式(contentScale),以及在生产环境中保证加载稳定性与性能。
4.1 核心原理
Image 组件的本质是一个接收 Painter 的容器。Painter 定义了绘制方式和内容源。本地图片通过 painterResource 函数读取 drawable 资源,返回 Painter 对象;网络图片则需要引入第三方图片加载库(Coil 或 Glide),它们提供 rememberAsyncImagePainter 等 API,将 URL 转为可延迟加载的 Painter。占位图、错误图、过渡动画等均通过加载库的配置实现。
4.2 本地图片加载
使用 painterResource 加载 drawable 文件夹下的资源(png、webp、vector),无需额外依赖。
Image(
painter = painterResource(id = R.drawable.ic_launcher),
contentDescription = "应用图标",
contentScale = ContentScale.Fit
)
对于 mipmap 或 android.resource:// 路径,可用 rememberResourcePainter(需要 @Composable 环境)。
4.3 网络图片加载(Coil)
Coil 是 Compose 官方推荐的 Kotlin 协程图片加载库,添加依赖后可直接使用 AsyncImage 或 rememberAsyncImagePainter。
implementation("io.coil-kt:coil-compose:2.6.0")
4.3.1 基本用法:AsyncImage
AsyncImage(
model = "https://example.com/photo.jpg",
contentDescription = "网络图片",
placeholder = painterResource(R.drawable.placeholder),
error = painterResource(R.drawable.error),
contentScale = ContentScale.Crop
)
4.3.2 使用 rememberAsyncImagePainter(更灵活)
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.data("https://example.com/photo.jpg")
.crossfade(true) // 渐变动画
.size(Size(300, 300)) // 裁剪尺寸,减少内存
.build()
)
Image(
painter = painter,
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth()
)
4.4 网络图片加载(Glide)
Glide 在 Compose 中通过 compose 扩展库实现,添加依赖后使用 GlideImage 或 rememberGlidePainter。
com.github.bumptech.glide:compose:1.0.0-rc02。
// 使用 GlideImage
GlideImage(
model = "https://example.com/photo.jpg",
contentDescription = "Glide网络图片",
loading = painterResource(R.drawable.loading),
failure = painterResource(R.drawable.error)
)
4.5 contentScale 缩放模式
ContentScale 决定图片如何适应 Image 的边界,常见选项如下表:
| 缩放模式 | 效果 | 适用场景 |
|---|---|---|
| ContentScale.Fit | 保持宽高比,完整显示图片,可能留白 | 图标、不需要裁剪的图 |
| ContentScale.Crop | 保持宽高比,填充整个区域,裁剪边缘 | 头像、封面图 |
| ContentScale.FillBounds | 拉伸以填满边界,不保持比例 | 背景、图案填充 |
| ContentScale.FillWidth | 宽度填满,高度自适应,保持比例 | 横屏全宽图片 |
| ContentScale.Inside | 如果图片比容器小,不放大;否则等比缩小 | 防止超大图溢出 |
Crop 保证显示区无空白;宽屏 Banner 使用 FillWidth 配合高度约束。
4.6 实现流程总结
加载一张网络图片的标准化步骤:
- 添加图片加载库依赖(Coil / Glide)
- 在 Composable 函数中,使用
rememberAsyncImagePainter或AsyncImage创建 painter - 在
ImageRequest.Builder中设置:URL、placeholder、error、crossfade、size 等 - 将 painter 传入
Image组件,指定contentScale - 为
Image添加Modifier控制尺寸(size、fillMaxWidth等)
4.7 调试与部署
- 调试:在
AsyncImage或rememberAsyncImagePainter的ImageRequest.Builder中添加.listener(onStart = ..., onSuccess = ..., onError = ...)观察加载状态。 - 部署检查:确认网络库版本与
compileSdk匹配;Coil 内部依赖 OkHttp,避免版本冲突。 - 图片尺寸:生产环境总是通过
size(Size(x, y))限制解码尺寸,防止 OOM。
4.8 常见错误与解决方法
| 错误现象 | 原因 | 解决 |
|---|---|---|
| 图片不显示,无错误 | URL 错误 / 无网络权限 | 检查 Manifest 中 INTERNET 权限;使用 base64 测试 |
| OOM / 卡顿 | 加载原图过大 | 添加 size(Size(...)) 或使用 coil.transform 压缩 |
| placeholder 不显示 | 未正确设置 placeholder | 使用 painterResource 确保资源存在 |
| 白色闪烁 | 未开启 crossfade 或过渡动画 | Coil: .crossfade(true); Glide: .transition(...) |
| 图片变形 | contentScale 选用不当 | 根据 UI 需求选择 Crop 或 Fit |
4.9 性能与稳定性优化
- 内存优化:Coil 默认使用
Bitmap.Config.HARDWARE减少内存;Glide 使用asBitmap()指定格式。 - 磁盘缓存管理:Coil 通过
Coil.imageLoader(LocalContext.current)自定义缓存大小;Glide 可通过RequestOptions.diskCacheStrategy()控制。 - 预加载:在列表滑动前使用
coil.imageLoader().enqueue(ImageRequest.Builder(context).data(url).build())提前下载。 - 生命周期绑定:Coil/Glide 自动感知 Composable 生命周期,在退出时取消请求,无需手动管理。
- 矢量图适配:本地矢量图(VectorDrawable)使用
painterResource,避免使用Image时被contentScale拉伸模糊;设置tint时使用ColorFilter.tint(Color.Red)。
// Application 中
ImageLoader.Builder(context)
.memoryCachePolicy(CachePolicy.ENABLED)
.memoryCache {
MemoryCache.Builder(context)
.maxSizePercent(0.25)
.build()
}
.diskCache {
DiskCache.Builder()
.directory(cacheDir.resolve("coil_cache"))
.maxSize(100 * 1024 * 1024)
.build()
}
.crossfade(true)
.build()