如何使用Kotlin实现带圆点指示器的Android自动轮播图
Kotlin 原生实现Android带圆点指示器的自动轮播图
以下实现全靠原生组件,无需引入第三方轮播库。
1. 准备圆点状态资源
在res/drawable目录下新建两个shape文件:
dot_selected.xml(选中状态圆点)
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="@color/white" /> <size android:width="8dp" android:height="8dp" /> </shape>
dot_unselected.xml(未选中状态圆点)
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="@color/gray" /> <size android:width="8dp" android:height="8dp" /> </shape>
2. 编写布局文件
主页面布局(示例:activity_main.xml)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/vp_banner" android:layout_width="match_parent" android:layout_height="200dp" /> <LinearLayout android:id="@+id/ll_indicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal" android:paddingVertical="8dp" /> </LinearLayout>
轮播Item布局(item_banner.xml)
<?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/iv_banner" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" />
3. 实现轮播适配器
class BannerAdapter(private val imageList: List<Int>) : RecyclerView.Adapter<BannerAdapter.BannerViewHolder>() { inner class BannerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val ivBanner: ImageView = itemView.findViewById(R.id.iv_banner) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BannerViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_banner, parent, false) return BannerViewHolder(view) } override fun onBindViewHolder(holder: BannerViewHolder, position: Int) { // 无限轮播取真实位置 val realPosition = position % imageList.size holder.ivBanner.setImageResource(imageList[realPosition]) // 若加载网络图片,替换为Glide/Coil加载逻辑即可 } override fun getItemCount(): Int { // 返回Int最大值实现虚拟无限轮播 return Int.MAX_VALUE } }
4. Activity中完成逻辑绑定
class MainActivity : AppCompatActivity() { // 替换为你的轮播图片资源列表 private val bannerImages = listOf(R.drawable.banner1, R.drawable.banner2, R.drawable.banner3) private lateinit var vpBanner: ViewPager2 private lateinit var llIndicator: LinearLayout private val bannerScope = CoroutineScope(Dispatchers.Main) private var currentPos = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) vpBanner = findViewById(R.id.vp_banner) llIndicator = findViewById(R.id.ll_indicator) initIndicator() initBanner() startAutoScroll() } private fun initIndicator() { llIndicator.removeAllViews() for (i in bannerImages.indices) { val dot = ImageView(this) val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT) params.marginStart = 4.dpToPx() params.marginEnd = 4.dpToPx() dot.layoutParams = params // 默认第一个圆点选中 dot.setImageDrawable(if (i == 0) getDrawable(R.drawable.dot_selected) else getDrawable(R.drawable.dot_unselected)) llIndicator.addView(dot) } } private fun initBanner() { val adapter = BannerAdapter(bannerImages) vpBanner.adapter = adapter // 初始位置设到中间,避免用户一开始滑到边界 vpBanner.setCurrentItem(bannerImages.size * 100, false) // 监听页面切换更新指示器 vpBanner.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { super.onPageSelected(position) currentPos = position val realPos = position % bannerImages.size // 更新所有圆点状态 for (i in bannerImages.indices) { val dot = llIndicator.getChildAt(i) as ImageView dot.setImageDrawable(if (i == realPos) getDrawable(R.drawable.dot_selected) else getDrawable(R.drawable.dot_unselected)) } } }) } private fun startAutoScroll() { bannerScope.launch { while (isActive) { delay(3000) // 3秒切换一次,可自行调整 currentPos += 1 vpBanner.setCurrentItem(currentPos, true) } } } // dp转px扩展方法 private fun Int.dpToPx(): Int { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), resources.displayMetrics).toInt() } override fun onDestroy() { super.onDestroy() // 销毁时停止协程,避免内存泄漏 bannerScope.cancel() } }
如果需要支持手势滑动暂停轮播,可在OnPageChangeCallback的onPageScrollStateChanged方法中监听拖拽状态,临时停止轮播,松手后再恢复即可。
内容的提问来源于stack exchange,提问作者Divya
相关产品推荐
相关产品推荐

