翻译:English
AsyncImage 是一个异步执行图片请求并呈现结果的可组合函数,你可以直接使用它加载图片,如下:
// val imageUri = "/Users/my/Downloads/image.jpg"
// val imageUri = file:///compose_resource/composeResources/com.github.panpf.sketch.sample.resources/files/sample.png
val imageUri = "https://example.com/image.jpg"
AsyncImage(
uri = imageUri,
contentDescription = "photo"
)
AsyncImage(
uri = imageUri,
state = rememberAsyncImageState(ComposableImageOptions {
placeholder(Res.drawable.placeholder)
error(Res.drawable.error)
crossfade()
// There is a lot more...
}),
contentDescription = "photo"
)
AsyncImage(
rqeuest = ComposableImageRequest(imageUri) {
placeholder(Res.drawable.placeholder)
error(Res.drawable.error)
crossfade()
// There is a lot more...
},
contentDescription = "photo"
)
Tip
placeholder(Res.drawable.placeholder)
需要导入 sketch-compose-resources
模块
SubcomposeAsyncImage 是 AsyncImage 的变体,它允许你完全自主的绘制内容,如下:
SubcomposeAsyncImage(
uri = "https://example.com/image.jpg",
loading = {
Text("Loading")
},
contentDescription = "photo"
)
SubcomposeAsyncImage(
uri = "https://example.com/image.jpg",
contentDescription = "photo",
content = {
when (state.painterState) {
is PainterState.Loading -> {
Text("Loading")
}
is PainterState.Error -> {
Text("Error")
}
else -> {
Image(
painter = painter,
contentDescription = "photo"
)
}
}
}
)
Tip
SubcomposeAsyncImage 的性能可能不如 AsyncImage,因此这种组合可能不适合对性能至关重要的列表部分
如果你必须使用 Image 组件,那么你还可以直接使用 AsyncImagePainter 来加载图片,如下:
Image(
painter = rememberAsyncImagePainter(uri = "https://example.com/image.jpg"),
contentDescription = "photo"
)
Image(
painter = rememberAsyncImagePainter(
rqeuest = ComposableImageRequest("https://example.com/image.jpg") {
placeholder(Res.drawable.placeholder)
error(Res.drawable.error)
crossfade()
// There is a lot more...
}
),
contentDescription = "photo"
)
Tip
Image + AsyncImagePainter
会比 AsyncImage 会略慢一些,这是由于 [Sketch] 依赖组件的确切大小才会开始加载图片,AsyncImage 在布局阶段就可以获取到组件的大小,而Image + AsyncImagePainter
则是要等到绘制阶段才能获取到组件大小。- 如果在 Image 上修改了 contentScale,则也要同步修改 rememberAsyncImagePainter 的 contentScale
placeholder(Res.drawable.placeholder)
需要导入sketch-compose-resources
模块
AsyncImageState 是 AsyncImage 和 AsyncImagePainter 的核心。AsyncImageState 负责执行 ImageRequest 和管理状态,AsyncImagePainter 负责从 AsyncImageState 读取 Painter 并绘制,AsyncImage 负责布局
你可以从 AsyncImageState 读取请求的状态、进度、Painter,你还可以通过其 restart() 方法重新加载图片,如下:
val state = rememberAsyncImageState()
AsyncImage(
uri = "https://example.com/image.jpg",
contentDescription = "photo",
state = state,
)
val result: ImageResult? = state.result
val loadState: LoadState? = state.loadState
val request: ImageRequest = loadState.request
when (loadState) {
is Started -> {
}
is Success -> {
val cacheKey: String = loadState.result.cacheKey
val imageInfo: ImageInfo = loadState.result.imageInfo
val dataFrom: DataFrom = loadState.result.dataFrom
val resize: Resize = loadState.result.resize
val transformeds: List<String>? = loadState.result.transformeds
val extras: Map<String, String>? = loadState.result.extras
}
is Error -> {
val throwable: Throwable = loadState.result.throwable
}
is Canceled -> {}
else -> {
// null
}
}
val progress: Progress? = state.progress
val painterState: PainterState = state.painterState
when (painterState) {
is Loading -> {}
is Success -> {}
is Error -> {}
}
val painter: Painter? = state.painter
// 重新加载
state.restart()
在使用 AsyncImage、SubcomposeAsyncImage 以及 AsyncImagePainter 时你不能调用 ImageRequest 的 addListener()、addProgressListener() 方法,这会导致 App 崩溃
原因是 Listener、ProgressListener 在使用的时候时都大部分情况下都是直接 new 一个新的实例,这会导致 ImageRequest 的 equals 结果是 false 而触发重组,从而降低性能
因此你必须用 AsyncImageState 的 loadState 和 progress 属性来代替 addListener() 、addProgressListener()
在使用 AsyncImage、SubcomposeAsyncImage 以及 AsyncImagePainter 时你不能调用 ImageRequest 的 target() 方法,这会导致 App 崩溃,因为 Target 必须由 AsyncImageState 配置