Accompanist
Google 为 Compose 提供的额外支持库,添补了 Jetpack Compose 缺少的一些常用功能,官方说这些库最终会被整合到 Compose 中(Insets 已经被整合到 1.2.0 版本中了)。 Git 地址 、文档地址。
- Pager 类似 ViewPager ,作为 Banner 组件的容器
- pager-indicators 和 Pager 联用的指示器
- Placeholder Banner 图片加载时的占位,项目中其他位置也可以使用,数据初始化时可以实现骨架屏的效果。
Placeholder 有 Placeholder Foundation 和 Placeholder Material 两个库,后者依赖前者默认使用了 Material 主题中的颜色。这两个库选择一个引入依赖即可。
Coil
官方推荐的图片加载库,Git 地址。
自定义 Banner 容器
容器是个水平方向的 Pager 。
- items : Banner 要显示的数据
- onItemClick :item 点击事件
- activeIndicatorColor :当前页所在页指示器的颜色
- inactiveIndicatorColor :非当前页所在页指示器的颜色
- itemContent :每个 item 对应在 Pager 中的具体页面
@OptIn(ExperimentalPagerApi::class)
@Composable
fun <T> Banner(
modifier: Modifier = Modifier,
items: List<T>,
onItemClick: ((T) -> Unit)? = null,
activeIndicator: Color = Color.Magenta,
inactiveIndicator: Color = Color.Gray,
itemContent: @Composable (T) -> Unit
) {
val pagerState = rememberPagerState()
HorizontalPager(
state = pagerState,
count = items.size,
modifier = Modifier
//点击事件
.clickable {
onItemClick?.invoke((items[pagerState.currentPage]))
}
.then(modifier)
) { pageIndex ->
val itemData = items[pageIndex]
Box(modifier = Modifier
.height(IntrinsicSize.Min)
.fillMaxWidth()) {
//内容
itemContent(itemData)
//指示器
HorizontalPagerIndicator(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(8.dp),
pagerState = pagerState,
activeColor = activeIndicatorColor,
inactiveColor = inactiveIndicatorColor
)
}
}
}
自定义 BannerItem
显示图片的 BannerItem , 图片加载时显示 placeHolder。
@Composable
fun ImageBannerItem(imageUrl:String,modifier: Modifier = Modifier){
var placeHolderVisible by remember { mutableStateOf(true) }
AsyncImage(
model = imageUrl,
contentDescription = "",
contentScale = ContentScale.Crop,
modifier = Modifier
.fillMaxWidth()
.placeholder(visible = placeHolderVisible, highlight = PlaceholderHighlight.fade())
.then(modifier),
onState = {
when (it) {
is AsyncImagePainter.State.Success -> {
placeHolderVisible = false
}
is AsyncImagePainter.State.Error -> {
//todo 异常处理
Log.e("AsyncImage", "ImageBannerItem:State.Error ${it.result.throwable} ")
}
}
}
)
}
WanAndroid Banner 实现
修改 UiHome 。
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun UiHome(navController: NavController,viewModel: HomeViewModel = hiltViewModel()){
val homeState = rememberHomeState(viewModel = viewModel, navController = navController)
Scaffold { paddingValues ->
Column (modifier = Modifier.padding(paddingValues)){
Banner(items = homeState.banners) {
ImageBannerItem(modifier = Modifier.height(200.dp),imageUrl = it.imagePath)
}
}
}
}
(总算能贴上张图了 -。-)
So easy! , 组合形式的自定义 Compose 组件就这么简单,类似 Compose Material 组件的实现方式,定义好槽位后将内容声明成参数即可。
Banner 还欠缺了自动滚动功能,添加自动滚动功能涉及到 Compose side-effect APIs 和手势处理知识,放到下一章完成。