制造一个JetpackCompose Material3轮播图
视频教程
JetpackCompose快速制造轮播图(banner)_哔哩哔哩_bilibili
作用
网络图片加载库Coil
implementation("io.coil-kt:coil-compose:2.4.0")
核心组件
Coil(AsyncImage)+HorizontalPager+LaunchedEffect
测试数据
val imgList = listOf(
"https://www.6hu.cc/wp-content/uploads/2023/07/1689363185-921c678c98763f5.png",
"https://www.6hu.cc/wp-content/uploads/2023/07/1689363192-2568af85285a6e3.png",
"https://www.6hu.cc/wp-content/uploads/2023/07/1689363198-aad6753967406ad.jpg"
)
状况变量
setContent {
//HorizontalPager的状况
val pagerState = rememberPagerState()
//当时翻滚到了哪哪一个页面
val nowPageIndex = pagerState.currentPage
//用于点击指示器的时分发动协程进行HorizontalPager方位手动更新
val scope = rememberCoroutineScope()
//......
}
Banner结构
Box { //这样指示器就能够掩盖在轮播图上
HorizontalPager(
state = pagerState,
//不让一个图最宽,留空能够一个页面渲染出多个图
contentPadding = PaddingValues(horizontal = 50.dp),
modifier = Modifier
.height(180.dp)
.padding(top = 15.dp),
pageCount = imgList.size
) { index ->
//激活项的缩放过渡
val imgScale by animateFloatAsState(
targetValue = if (nowPageIndex == index) 1f else 0.8f,
animationSpec = tween(300), label = ""
)
//使用Coil加载网络图片
AsyncImage(
modifier = Modifier
.fillMaxSize()
.scale(imgScale)
.clip(
RoundedCornerShape(10.dp) //轮播图圆角裁剪
),
model = ImageRequest
.Builder(LocalContext.current)
.data(imgList[index])
.scale(Scale.FILL)
.build(),
contentDescription = "图片$index",
contentScale = ContentScale.FillBounds
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(bottom = 5.dp),
horizontalArrangement = Arrangement.Center
) {
//循环渲染指示器
imgList.indices.forEach { radioIndex ->
RadioButton(selected = nowPageIndex == radioIndex, onClick = {
//点击的时分发动协程手动进行HorizontalPager的页面翻滚
scope.launch {
pagerState.animateScrollToPage(radioIndex)
}
})
}
}
}
定时器
//调查pagerState.settledPage,已确保翻滚结束再进行下一次自动轮播
LaunchedEffect(pagerState.settledPage) {
delay(1500)//推迟1.5s翻滚
//判别下一次翻滚索引是否越界
val scroller =
if (pagerState.currentPage + 1 == imgList.size) 0 else pagerState.currentPage + 1
//手动进行HorizontalPager的页面翻滚
pagerState.animateScrollToPage(scroller)
}
完整代码
class MainActivity : ComponentActivity() {
@OptIn(ExperimentalFoundationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val imgList = listOf(
"https://www.6hu.cc/wp-content/uploads/2023/07/1689363185-921c678c98763f5.png",
"https://www.6hu.cc/wp-content/uploads/2023/07/1689363192-2568af85285a6e3.png",
"https://www.6hu.cc/wp-content/uploads/2023/07/1689363198-aad6753967406ad.jpg"
)
setContent {
val pagerState = rememberPagerState()
val nowPageIndex = pagerState.currentPage
val scope = rememberCoroutineScope()
LaunchedEffect(pagerState.settledPage) {
delay(1500)
val scroller =
if (pagerState.currentPage + 1 == imgList.size) 0 else pagerState.currentPage + 1
pagerState.animateScrollToPage(scroller)
}
ComposeLearnTheme {
Box {
HorizontalPager(
state = pagerState,
contentPadding = PaddingValues(horizontal = 50.dp),
modifier = Modifier
.height(180.dp)
.padding(top = 15.dp),
pageCount = imgList.size
) { index ->
val imgScale by animateFloatAsState(
targetValue = if (nowPageIndex == index) 1f else 0.8f,
animationSpec = tween(300), label = ""
)
AsyncImage(
modifier = Modifier
.fillMaxSize()
.scale(imgScale)
.clip(
RoundedCornerShape(10.dp)
),
model = ImageRequest
.Builder(LocalContext.current)
.data(imgList[index])
.scale(Scale.FILL)
.build(),
contentDescription = "图片$index",
contentScale = ContentScale.FillBounds
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(bottom = 5.dp),
horizontalArrangement = Arrangement.Center
) {
imgList.indices.forEach { radioIndex ->
RadioButton(selected = nowPageIndex == radioIndex, onClick = {
scope.launch {
pagerState.animateScrollToPage(radioIndex)
}
})
}
}
}
}
}
}
}