Compose 图片加载新姿势 — Coil 新手基础教程

如果你在 Compose 下开发应用,那么图片加载库,一定会用 Coil

本文将介绍 Coil 的基础用法,手把手带你掌握 Coil 在 Compose 中的应用,让图片加载简单高效。

来者何人

Coil 是适用于 Android 和 Compose Multiplatform 的图像加载库。它具有以下特点:

  • 快速:Coil 执行多项优化,包括内存和磁盘缓存、图像降采样、自动暂停/取消请求等。
  • 轻量:Coil 仅依赖于 Kotlin、Coroutines 和 Okio,可与 Google 的 R8 代码压缩器无缝协作。
  • 易于使用:Coil 的 API 利用 Kotlin 的语言功能实现简单性并减少样板代码。
  • 现代:Coil 是 Kotlin 优先的,可与 Compose、Coroutines、OkioOkHttpKtor 等现代库互操作。

为什么是 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"
)

加载占位图会在下载网络图片的时候显示,失败占位图会在图片下载失败的时候展示,而空数据占位图,则在参数 modelnull 的时候展示。

我将使用如下三张图片分别作为失败,加载中,空数据的占位图,每张图片均是 128 像素的大小。

当源图片加载中的时候:

实际上这时候的效果是有问题的,你会发现加载占位图太大了,占满了整个区域,没关系,一会儿解决。

如果网络有问题,或者给的图片的 URL 有问题,则会显示失败的占位图:

如果 modelnull

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,想知道内存优化、视频封面加载、占位图动效等怎么做,那么下一篇文章,你一定要看!

相关推荐
李艺为3 小时前
Fake Device Test作假屏幕分辨率分析
android·java
zh_xuan3 小时前
github远程library仓库升级
android·github
峥嵘life4 小时前
Android蓝牙停用绝对音量原理
android
小书房4 小时前
Kotlin的内联函数
java·开发语言·kotlin·inline·内联函数
czlczl200209255 小时前
IN和BETWEEN在索引效能的区别
android·adb
Volunteer Technology5 小时前
ES高级搜索功能
android·大数据·elasticsearch
北京自在科技5 小时前
Find Hub App 小更新
android·ios·安卓·findmy·airtag
lbb 小魔仙6 小时前
2026远程办公软件夏季深度横测:ToDesk、向日葵、网易UU远程全面对比,远控白皮书
android·服务器·网络协议·tcp/ip·postgresql
coding_fei6 小时前
AudioServer初始化过程
android
brucelee1866 小时前
Docker 运行 Android 模拟器
android·docker·容器