
如果你在 Compose 下开发应用,那么图片加载库,一定会用 Coil。
本文将介绍 Coil 的基础用法,手把手带你掌握 Coil 在 Compose 中的应用,让图片加载简单高效。
来者何人

Coil 是适用于 Android 和 Compose Multiplatform 的图像加载库。它具有以下特点:
- 快速:Coil 执行多项优化,包括内存和磁盘缓存、图像降采样、自动暂停/取消请求等。
- 轻量:Coil 仅依赖于 Kotlin、Coroutines 和 Okio,可与 Google 的 R8 代码压缩器无缝协作。
- 易于使用:Coil 的 API 利用 Kotlin 的语言功能实现简单性并减少样板代码。
- 现代:Coil 是 Kotlin 优先的,可与 Compose、Coroutines、Okio 、OkHttp 和 Ktor 等现代库互操作。
为什么是 Coil 这个单词?
Co routine I mage Loader。
在正式开始讲解之前,我们会用到一张图片:

一张 1920 x 1080 的图片
快速入门
Kotlin
const val PIC_URL = "https://images.unsplash.com/photo-1604156788856-2ce5f2171cce?fm=jpg&q=60&w=1920"
AsyncImage(
model = PIC_URL,
contentDescription = "ballon"
)
是的,基本上你不用任何配置,在 Compose 中,直接使用 AsyncImage
就可以加载一张图片,PIC_URL
指向一张在线图片地址。
在平板中,显示效果是这样的:

如果你什么都不设置,AsyncImage
会自动使用原图大小直到占满整个布局。
引入依赖
OK,虽然我们已经学会了如何使用 AsyncImage
,但是,我还没有告诉你如何引入依赖呢。
如果你是初学者,我建议你直接使用 bom 配置:
Kotlin
val coilBom = platform("io.coil-kt.coil3:coil-bom:3.3.0")
implementation(coilBom)
implementation("io.coil-kt.coil3:coil-compose")
implementation("io.coil-kt.coil3:coil-network-okhttp")
coil-bom
会帮助你进行版本管理,在后续使用 Coil 其他组件的时候,我们只需要生命组件的名称,而无需特定声明版本。
compose-bom
也是这么工作的。
好的,在引入简单的依赖之后,上述代码,便可以运行,你可以尝试运行在自己的机器上看看效果。
AyncImage
AsyncImage
是一个可组合函数,它异步执行图像请求并渲染结果。
它的用法和 Compose 的 Image
几乎是一样的。
接下来我们展示一下 AsyncImage
的一些基本用法。为了让效果看起来更明显,我们会给 AsyncImage
一个默认的黑色背景:
Kotlin
AsyncImage(
modifier = Modifier.size(400.dp).background(Color.Black), // 黑色背景表示控件区域
model = PIC_URL,
contentScale = ContentScale.Crop,
contentDescription = "ballon"
)
这里使用了一个 contentScale
参数。
ContentScale
表示一种规则,他表示一种对源图片进行缩放,使其显示在目标矩形的一种规则。
此处我们使用了 ContentScale.Crop
,它会均匀的对源图片进行缩放,当其一条边满足目标矩形的时候,便停止。
我们看下效果:

你会发现,源图片优先满足了高,然后居中显示,对长进行了裁剪。它类似于 android.widget.ImageView.ScaleType.CENTER_CROP
。
如果我们想对裁剪的方向进行控制,可以结合 alignment
。
Kotlin
AsyncImage(
modifier = Modifier.size(400.dp).background(Color.Black),
model = PIC_URL,
contentScale = ContentScale.Crop,
alignment = Alignment.CenterStart, // 从左中开始裁剪
contentDescription = "ballon"
)

对比原图,这一次确实是从头开始裁剪,并不是居中裁剪了。
如果你想整体居中显示:
Kotlin
AsyncImage(
modifier = Modifier.size(400.dp).background(Color.Black),
model = PIC_URL,
contentScale = ContentScale.Inside,
contentDescription = "ballon"
)
ContentScale.Inside
正是你想要的:

注意黑色区域,证明没有铺满整个 AsyncImage
,达到了居中显示的效果
当我们配合 Alignment.BottomCenter
控制显示区域:

占位图
网络图片是有加载过程的,所以,很多图片加载库会提供占位图来提升用户体验,Coil 也不例外。
Coil 提供三种占位图,分别是加载中,失败,以及空数据:
Kotlin
AsyncImage(
modifier = Modifier.size(400.dp).background(Color.Black),
model = PIC_URL,
contentScale = ContentScale.Crop,
error = painterResource(R.drawable.icn_failed), // 失败占位图
placeholder = painterResource(R.drawable.icn_loading),// 加载占位图
fallback = painterResource(R.drawable.icn_null), // 空数据占位图
contentDescription = "ballon"
)
加载占位图会在下载网络图片的时候显示,失败占位图会在图片下载失败的时候展示,而空数据占位图,则在参数 model
是 null
的时候展示。
我将使用如下三张图片分别作为失败,加载中,空数据的占位图,每张图片均是 128
像素的大小。

当源图片加载中的时候:

实际上这时候的效果是有问题的,你会发现加载占位图太大了,占满了整个区域,没关系,一会儿解决。
如果网络有问题,或者给的图片的 URL 有问题,则会显示失败的占位图:

如果 model
是 null
:
Kotlin
//...
model = null,
//...

则显示空数据占位图。
好的,现在我们修正一下显示效果。
正如我在记载占位图提到的,这个效果是有问题的,因为一般 UI 提供的占位图是比较小的,它的 contentScale
参数不能和源图片一样,所以这里我们要动态调整一下 contentScale
。
幸好,AsyncImage
已经做好了这一切。
AsyncImage
支持加载相关的一系列回调,
Kotlin
//...
onLoading: ((State.Loading) -> Unit)? = null, // 加载中
onSuccess: ((State.Success) -> Unit)? = null, // 成功
onError: ((State.Error) -> Unit)? = null, // 失败
//...
我们使用这些回调,动态的修改 contentScale
:
Kotlin
var succeed by remember { mutableStateOf(false) } // 图片加载是否成功
AsyncImage(
modifier = Modifier.size(400.dp).background(Color.Black),
model = PIC_URL,
contentScale = if (succeed) ContentScale.Crop else ContentScale.Inside, // 调整
error = painterResource(R.drawable.icn_failed),
placeholder = painterResource(R.drawable.icn_loading),
fallback = painterResource(R.drawable.icn_null),
onLoading = {
succeed = false // 接收回调
},
onError = {
succeed = false // 接收回调
},
onSuccess = {
succeed = true // 接收回调
},
contentDescription = "ballon"
)
好的,我们来看下效果:

未完待续
如果你只是想简单使用 Coil,那么本篇文章教你的这些,已经够用了,甚至很多大型项目,基本也就这么用。
但如果你想更深入了解 Coil,想知道内存优化、视频封面加载、占位图动效等怎么做,那么下一篇文章,你一定要看!