本文已参与「新人创作礼」活动,一起开启掘金创作之路。
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)
)