栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android:使用Jetpack Compose实现自动轮播Banner

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android:使用Jetpack Compose实现自动轮播Banner

系列文章目录
  • Android: Jetpack Compose如何禁用涟漪(水波纹)效果
  • Android:使用Jetpack Compose 实现Text控件跑马灯效果
  • Android:使用Jetpack Compose实现自动轮播Banner

文章目录
  • 系列文章目录
  • 前言
  • 一、先看效果
  • 二、实现思路
  • 三、源码
  • 四、使用示例
  • 总结


前言

自动轮播Banner 相信大多数APP 都会有此需求,本文主要是使用Compose 来实现自动无限轮播图效果。


一、先看效果

二、实现思路
  • 无限循环
    思路:这里是将item数量设为无限大,然后计算出原始数据集合中的对应数据进行展示。
  • 定时切换
    思路:使用LaunchedEffect启动协程,死循环并间隔1s进行Pager切换。

需要注意的是:在手势拖动时,要关闭定时切换。

三、源码

代码如下:

@OptIn(ExperimentalPagerApi::class)
@Composable
fun Banner(imgs: ArrayList) {
    val pageCount = imgs.size
    val loopingCount = Int.MAX_VALUE
    val startIndex = loopingCount / 2
    val pagerState = rememberPagerState(initialPage = startIndex)

    // 页码转换
    fun pageMapper(index: Int) = (index - startIndex).floorMod(pageCount)

    Box {
        HorizontalPager(
            count = loopingCount, state = pagerState,
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 14.dp)
                .aspectRatio(2.45f)
        ) { index ->
            // 计算页面下标
            val page = pageMapper(index)
            BannerItem(imgUrl = imgs[page])
        }
        HorizontalPagerIndicator(
            pagerState = pagerState,
            activeColor = Blue,
            inactiveColor = WhiteAlpha50,
            indicatorWidth = 10.dp,
            indicatorHeight = 4.dp,
            spacing = 5.dp,
            pageCount = pageCount,
            pageIndexMapping = ::pageMapper,
            modifier = Modifier
                .align(
                    Alignment.BottomCenter
                )
                .padding(bottom = 8.dp)
        )

        var underDragging by remember {
            mutableStateOf(false)
        }

        LaunchedEffect(key1 = Unit) {
            pagerState.interactionSource.interactions.collect { interaction ->
                when (interaction) {
                    is PressInteraction.Press -> underDragging = true
                    is PressInteraction.Release -> underDragging = false
                    is PressInteraction.Cancel -> underDragging = false
                    is DragInteraction.Start -> underDragging = true
                    is DragInteraction.Stop -> underDragging = false
                    is DragInteraction.Cancel -> underDragging = false
                }
            }
        }

        if (underDragging.not()) {
            LaunchedEffect(key1 = underDragging) {
                try {
                    while (true) {
                        delay(1000L)
                        val current = pagerState.currentPage
                        val currentPos = pageMapper(current)
                        val nextPage = current + 1
                        if (underDragging.not()) {
                            val toPage =
                                nextPage.takeIf { nextPage < pagerState.pageCount }
                                    ?: (currentPos + startIndex + 1)
                            if (toPage > current) {
                                pagerState.animateScrollToPage(toPage)
                            } else {
                                pagerState.scrollToPage(toPage)
                            }
                        }
                    }
                } catch (e: CancellationException) {
                }
            }
        }

    }
}

@Composable
fun BannerItem(imgUrl: String) {
    Box(modifier = Modifier.fillMaxSize()) {
        AsyncImage(
            model = imgUrl, contentDescription = null,
            contentScale = ContentScale.Crop,
            modifier = Modifier
                .fillMaxWidth()
                .padding(start = 16.dp, end = 16.dp)
                .clip(RoundedCornerShape(12.dp))
                .clickable {
                    // 点击事件
                }
        )
    }
}


private fun Int.floorMod(other: Int): Int = when (other) {
    0 -> this
    else -> this - floorDiv(other) * other
}
四、使用示例

代码如下:

	val bannerImg = remember {
        mutableStateOf(
            arrayListOf("https://gd-hbimg.huaban.com/e9198b5ec234b5f0b0e4473acf39b430ac47c1ee3f875-CjGaUR_fw658",
                "https://gd-hbimg.huaban.com/e9198b5ec234b5f0b0e4473acf39b430ac47c1ee3f875-CjGaUR_fw658",
                "https://gd-hbimg.huaban.com/e9198b5ec234b5f0b0e4473acf39b430ac47c1ee3f875-CjGaUR_fw658")
        )
    }
    // 自动轮播图
    Banner(bannerImg.value)

总结

以上就是今天要讲的内容,本文的源码已全部贴出,方便大家自取并快速使用。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1002905.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号