Compose
若要新增對 Compose UI 的支援,請匯入擴充函式庫:
implementation("io.coil-kt.coil3:coil-compose:3.3.0")接著使用 AsyncImage 可組合函式來載入並顯示圖片:
AsyncImage(
model = "https://example.com/image.jpg",
contentDescription = null,
)model 可以是 ImageRequest.data 的值,也可以是 ImageRequest 本身。contentDescription 設定了輔助功能服務用來描述此圖片所代表意義的文字。
AsyncImage
AsyncImage 是一個可組合函式,它會非同步地執行圖片請求並呈現結果。它支援與標準 Image 可組合函式相同的引數,此外,它還支援設定預留位置 (placeholder)、錯誤 (error)、備用 (fallback) 繪圖器,以及載入中 (onLoading)、成功 (onSuccess)、錯誤 (onError) 回呼。這是一個載入圖片並帶有圓形裁剪、淡入淡出效果和設定預留位置的範例:
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data("https://example.com/image.jpg")
.crossfade(true)
.build(),
placeholder = painterResource(R.drawable.placeholder),
contentDescription = stringResource(R.string.description),
contentScale = ContentScale.Crop,
modifier = Modifier.clip(CircleShape),
)何時使用此函式:
大部分情況下,優先使用 AsyncImage。它會根據可組合函式的約束條件以及提供的 ContentScale,正確判斷圖片應載入的尺寸。
rememberAsyncImagePainter
在內部,AsyncImage 和 SubcomposeAsyncImage 使用 rememberAsyncImagePainter 來載入 model。如果您需要一個繪圖器 (Painter) 而不是可組合函式,可以使用 rememberAsyncImagePainter 來載入圖片:
val painter = rememberAsyncImagePainter("https://example.com/image.jpg")rememberAsyncImagePainter 比 AsyncImage 和 SubcomposeAsyncImage 更具彈性,但它有幾個缺點(詳見下方)。
何時使用此函式:
如果您需要一個繪圖器 (Painter) 而不是可組合函式,或者您需要觀察 AsyncImagePainter.state 並根據其繪製不同的可組合函式,又或者您需要使用 AsyncImagePainter.restart 手動重新啟動圖片請求,此函式會很有用。
此函式的主要缺點是它不會偵測圖片在螢幕上載入的尺寸,並且始終以其原始尺寸載入圖片。您可以傳遞一個自訂的 SizeResolver 或使用 rememberConstraintsSizeResolver(AsyncImage 內部使用的就是它)來解決此問題。範例:
val sizeResolver = rememberConstraintsSizeResolver()
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalPlatformContext.current)
.data("https://example.com/image.jpg")
.size(sizeResolver)
.build(),
)
Image(
painter = painter,
contentDescription = null,
modifier = Modifier.then(sizeResolver),
)另一個缺點是,當使用 rememberAsyncImagePainter 時,即使圖片存在於記憶體快取中並將在第一個影格中繪製,AsyncImagePainter.state 在首次組合時也將始終為 AsyncImagePainter.State.Empty。
SubcomposeAsyncImage
SubcomposeAsyncImage 是 AsyncImage 的一個變體,它使用子組合 (subcomposition) 為 AsyncImagePainter 的狀態提供一個插槽 API,而不是使用繪圖器 (Painter)。這是一個範例:
SubcomposeAsyncImage(
model = "https://example.com/image.jpg",
loading = {
CircularProgressIndicator()
},
contentDescription = stringResource(R.string.description),
)此外,您可以使用其 content 引數和 SubcomposeAsyncImageContent(它會呈現當前狀態)來實現更複雜的邏輯:
SubcomposeAsyncImage(
model = "https://example.com/image.jpg",
contentDescription = stringResource(R.string.description)
) {
val state by painter.state.collectAsState()
if (state is AsyncImagePainter.State.Success) {
SubcomposeAsyncImageContent()
} else {
CircularProgressIndicator()
}
}!!! 注意 子組合 (Subcomposition) 比常規組合慢,因此此可組合函式可能不適合您 UI 中對效能要求較高的部分(例如 LazyList)。
何時使用此函式:
一般來說,如果您需要觀察 AsyncImagePainter.state 並且它不使用子組合 (subcomposition),則優先使用 rememberAsyncImagePainter 而不是此函式。
具體來說,此函式僅在您需要觀察 AsyncImagePainter.state 且不能像使用 rememberAsyncImagePainter 那樣在第一次組合和第一個影格時為 Empty 的情況下才有用。SubcomposeAsyncImage 使用子組合來獲取圖片的約束條件,因此其 AsyncImagePainter.state 會立即更新。
觀察 AsyncImagePainter.state
val painter = rememberAsyncImagePainter("https://example.com/image.jpg")
val state by painter.state.collectAsState()
when (state) {
is AsyncImagePainter.State.Empty,
is AsyncImagePainter.State.Loading -> {
CircularProgressIndicator()
}
is AsyncImagePainter.State.Success -> {
Image(
painter = painter,
contentDescription = stringResource(R.string.description)
)
}
is AsyncImagePainter.State.Error -> {
// 顯示一些錯誤 UI。
}
}轉場
您可以使用 ImageRequest.Builder.crossfade 啟用內建的淡入淡出 (crossfade) 轉場:
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data("https://example.com/image.jpg")
.crossfade(true)
.build(),
contentDescription = null,
)自訂的 Transition 不適用於 AsyncImage、SubcomposeAsyncImage 或 rememberAsyncImagePainter,因為它們需要 View 引用。CrossfadeTransition 由於內部特殊支援而能正常運作。
儘管如此,透過觀察 AsyncImagePainter.state,仍然可以在 Compose 中建立自訂轉場:
val painter = rememberAsyncImagePainter("https://example.com/image.jpg")
val state by painter.state.collectAsState()
if (state is AsyncImagePainter.State.Success && state.result.dataSource != DataSource.MEMORY_CACHE) {
// 執行轉場動畫。
}
Image(
painter = painter,
contentDescription = stringResource(R.string.description),
)預覽
AsyncImage/rememberAsyncImagePainter/SubcomposeAsyncImage 在 Android Studio 中的預覽行為由 LocalAsyncImagePreviewHandler 控制。預設情況下,它會嘗試在預覽環境中正常執行請求。預覽環境中網路存取已禁用,因此網路 URL 將始終失敗。
您可以像這樣覆寫預覽行為:
val previewHandler = AsyncImagePreviewHandler {
ColorImage(Color.Red.toArgb())
}
CompositionLocalProvider(LocalAsyncImagePreviewHandler provides previewHandler) {
AsyncImage(
model = "https://example.com/image.jpg",
contentDescription = null,
)
}這對於 AndroidX 的 Compose 預覽截圖測試函式庫 也很有用,它在相同的預覽環境中執行。
Compose 多平台資源
Coil 透過使用 Res.getUri 作為 model 參數來支援載入 Compose 多平台資源。範例:
AsyncImage(
model = Res.getUri("drawable/sample.jpg"),
contentDescription = null,
)!!! 注意 Coil 不支援 Res.drawable.image 及其他編譯安全引用。您必須改用 Res.getUri("drawable/image")。追蹤此問題以獲取更新。
