加载数据在Android开发中应该算是非常频繁的操作了,因此简单在Jetpack Compose中实现一个通用的加载微件
效果如下:
加载中(转圈圈)
加载完成(显示内容)
另外加载失败后显示失败并可以点击重试
实现
实现这个微件其实非常简单,无非就是根据不同的状态加载不同页面
加载状态Bean
首先把加载的状态抽象出来,写个数据类
sealed class LoadingState<out R> {
object Loading : LoadingState<Nothing>()
data class Failure(val error : Throwable) : LoadingState<Nothing>()
data class Success<T>(val data : T) : LoadingState<T>()
val isLoading
get() = this is Loading
val isSuccess
get() = this is Success<*>
}
复制代码
此处借鉴了朱江大佬写的玩安卓Compose版本,在此感谢
微件
然后就是加载了。考虑到加载一般耗时,所以用协程。
写成微件大概就是下面这个样子
private const val TAG = "LoadingWidget"
/**
* 通用加载微件
* @author [FunnySaltyFish](https://blog.funnysaltyfish.fun/)
* @param modifier Modifier 整个微件包围在Box中,此处修饰此Box
* @param loader 加载函数,返回值为正常加载出的结果
* @param loading 加载中显示的页面,默认为转圈圈
* @param failure 加载失败显示的页面,默认为文本,点击可以重新加载(retry即为重新加载的函数)
* @param success 加载成功后的页面,参数[T]即为返回的结果
*/
@Composable
fun <T> LoadingContent(
modifier: Modifier = Modifier,
loader : suspend ()->T,
loading : @Composable ()->Unit = { DefaultLoading() },
failure : @Composable (error : Throwable, retry : ()->Unit)->Unit = { error, retry->
DefaultFailure(error, retry)
},
success : @Composable (data : T?)->Unit
) {
var key by remember {
mutableStateOf(false)
}
val state : LoadingState<T> by produceState<LoadingState<T>>(initialValue = LoadingState.Loading, key){
value = try {
Log.d(TAG, "LoadingContent: loading...")
LoadingState.Success(loader())
}catch (e: Exception){
LoadingState.Failure(e)
}
}
Box(modifier = modifier){
when(state){
is LoadingState.Loading -> loading()
is LoadingState.Success<T> -> success((state as LoadingState.Success<T>).data)
is LoadingState.Failure -> failure((state as LoadingState.Failure).error){
key = !key
Log.d(TAG, "LoadingContent: newKey:$key")
}
}
}
}
复制代码
里面的默认页面如下:
@Composable
fun DefaultLoading() {
CircularProgressIndicator()
}
@Composable
fun DefaultFailure(error: Throwable, retry : ()->Unit) {
Text(text = stringResource(id = R.string.loading_error), modifier = Modifier.clickable(onClick = retry))
}
复制代码
使用起来也很简单直接
LoadingContent(
modifier = Modifier.align(CenterHorizontally) ,
loader = (vm.sponsorService::getAllSponsor)
) { sponsorList ->
sponsorList?.let{
Column {
SponsorList(it)
Text("加载完成")
}
}
}
复制代码
完整代码在这里:FunnyTranslation/ThanksScreen.kt
完了。
最后再自荐一下我的开源项目(就是上面那个链接),Jetpack Compose实现的翻译软件。不妨点个star,万一什么地方有用呢(逃~