本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Jetpack Compose¶
要支持Jetpack Compose, 需要引入扩展库:
implementation("io.coil-kt:coil-compose:2.2.0")
使用可组合函数AsyncImage
来加载并展示图片:
AsyncImage(
model = "https://example.com/image.jpg",
contentDescription = null
)
model
要么是ImageRequest.data
要么是ImageRequest
自身. contentDescription
设置了无障碍服务使用的文本, 描述了图片表示的东西.
AsyncImage¶
AsyncImage
是一个可组合函数, 用于异步执行图片请求并渲染结果. 它支持和标准Image
可组合函数相同的参数, 而且它额外地支持设置placeholder
/error
/fallback
painter 和onLoading
/onSuccess
/onError
回调. 下面的例子展示了如果在加载图片的时候设置circle crop, crossfade和placeholder:
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)
)
SubcomposeAsyncImage¶
SubcomposeAsyncImage
是AsyncImage
的变体, 使用subcomposition而非Painter
向AsyncImagePainter
的状态提供API. 写个例子看一下:
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 = painter.state
if (state is AsyncImagePainter.State.Loading || state is AsyncImagePainter.State.Error) {
CircularProgressIndicator()
} else {
SubcomposeAsyncImageContent()
}
}
Subcomposition要比常规组合性能差一些, 所以在需要高性能的场景下(比如lists), Subcomposition也是不适合这部分UI.
注意
如果使用ImageRequest.Builder.size
(比如size(Size.ORIGINAL)
)为ImageRequest
自定义大小, SubcomposeAsyncImage
将不会使用subcomposition, 因为它不需要向可组合项提供约束.
AsyncImagePainter¶
在内部, AsyncImage
和SubcomposeAsyncImage
使用AsyncImagePainter
加载model
. 如果你需要Painter
且不能使用AsyncImage
, 你可以使用rememberAsyncImagePainter
来加载图片:
val painter = rememberAsyncImagePainter("https://example.com/image.jpg")
rememberAsyncImagePainter
是低层级API, 可能在所以场景下不能表现地如预期一样.
注意
如果要在渲染AsyncImagePainter
的Image
上设置自定义ContentScale
, 你也应该在rememberAsyncImagePainter
里面设置. 决定加载图片的正确维度也很必要.
Observing AsyncImagePainter.state¶
图片请求需要大小来决定输出图片的维度. 默认情况下, AsyncImage
和AsyncImagePainter
可以决定请求的大小, 但是是在组合发生之后, 且在首帧绘制之前. 使用这种方式决定大小以最大化性能. 这意味着AsyncImagePainter.state
在首次组合的时候已经在加载
了 - 即使图片已经在内存缓存中存在并且将首帧绘制.
如果需要AsyncImagePainter.state
在首次组合期间保持最新, 请使用SubcomposeAsyncImage
或者通过ImageRequest.Builder.size
为图片请求设置自定义尺寸. 比如, AsyncImagePainter.state
在下下面的例子中在首次组合期间将总是保持最新:
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.data("https://example.com/image.jpg")
.size(Size.ORIGINAL) // Set the target size to load the image at.
.build()
)
if (painter.state is AsyncImagePainter.State.Success) {
// This will be executed during the first composition if the image is in the memory cache.
}
Image(
painter = painter,
contentDescription = stringResource(R.string.description)
)
Transitions¶
使用ImageRequest.Builder.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
的状态在Compose中创建自定义转场动画也是有可能的:
val painter = rememberAsyncImagePainter("https://example.com/image.jpg")
val state = painter.state
if (state is AsyncImagePainter.State.Success && state.dataSource != DataSource.MEMORY_CACHE) {
// Perform the transition animation.
}
Image(
painter = painter,
contentDescription = stringResource(R.string.description)
)