安卓开发中轮播图和其指示器的设置

在安卓开发中,轮播图(Carousel)是一种常见的UI组件,用于展示一系列图片或内容,用户可以左右滑动来切换不同的视图。轮播图通常用于展示广告、新闻、产品图片等。

轮播图的指示器(Indicator)则是用于告诉用户当前展示的是轮播图中的哪一项,以及总共有多少项。

一、定义布局

1、定义轮播图和指示器载体

  • 一个ViewPager2组件用于显示轮播图。
  • LinearLayout组件用于显示圆点指示器。
XML 复制代码
                    <androidx.constraintlayout.widget.ConstraintLayout
                        android:id="@+id/sc_vip_content_cl"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content">


                        <!--          轮播图          -->
                        <androidx.viewpager2.widget.ViewPager2
                            android:id="@+id/sc_vip_slideshow_vp"
                            android:layout_width="match_parent"
                            android:layout_height="@dimen/dp_216"
                            app:layout_constraintBottom_toTopOf="@+id/sc_vip_content_ll"
                            app:layout_constraintEnd_toEndOf="parent"
                            app:layout_constraintStart_toStartOf="parent"
                            app:layout_constraintTop_toTopOf="parent" />

                        <!-- 圆点指示器 -->
                        <LinearLayout
                            android:id="@+id/sc_vip_indicator"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="@dimen/dp_30"
                            android:gravity="center"
                            android:orientation="horizontal"
                            app:layout_constraintBottom_toBottomOf="@id/sc_vip_slideshow_vp"
                            app:layout_constraintEnd_toEndOf="parent"
                            app:layout_constraintHorizontal_bias="0.5"
                            app:layout_constraintStart_toStartOf="parent" />

                    </androidx.constraintlayout.widget.ConstraintLayout>

2、定义ViewPager2的布局页面

定义ViewPager2的布局页面来放轮播图需要展示的内容

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_218">

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/sc_vip_vp_iv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@drawable/sc_png_vip_banner1"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

二、定义Fragment作为轮播图的载体

这个Fragment布局文件用的是上面定义ViewPager2的布局页面,作为轮播图的展示载体

定义了一个名为 ScVipSlideshowVpFrag 的 Fragment 类,它继承自 BaseFragmentX 类,并且使用了 ScFragVipVpBinding 作为数据绑定类。这个 Fragment 用于展示单个图片,通常用在轮播图中。

以下是代码的详细解释:

**1、类定义:**定义了一个名为 ScVipSlideshowVpFrag 的类,它继承自 BaseFragmentX(封装过的),并且使用了 ScFragVipVpBinding 作为数据绑定类。

**2、Companion Object:**定义了一个伴生对象(Companion Object),它包含了一个常量 IMAGE_ID 和一个静态方法 getInstance()。 IMAGE_ID:用于在 Bundle 中存储图片资源ID。

**3、getInstance():**这是一个静态方法,用于创建 ScVipSlideshowVpFrag 实例,并设置图片资源ID。

**4、setLayoutId():**重写了 BaseFragmentX 中的 setLayoutId() 方法,返回布局文件的资源ID R.layout.sc_frag_vip_vp。

**5、onLazyLoad():**重写了 BaseFragmentX 中的 onLazyLoad() 方法,这个方法在 Fragment 可见时被调用。在这个方法中,从 arguments 中获取图片资源ID,并将其设置到布局中的图片视图 scVipVpIv 上。 这个 Fragment 类可以用于轮播图中的每个页面,展示单个图片。通过 getInstance() 方法,可以创建 ScVipSlideshowVpFrag 实例,并传递图片资源ID。在 onLazyLoad() 方法中,根据传递的图片资源ID设置图片视图。

Kotlin 复制代码
import android.os.Bundle
import com.mango.base.base.BaseFragmentX
import com.mango.sc.R
import com.mango.sc.databinding.ScFragVipVpBinding

/**
 * 
 * 顶部轮播图
 * */
class ScVipSlideshowVpFrag : BaseFragmentX<ScFragVipVpBinding>() {

    companion object {

        const val IMAGE_ID = "image_id"
        fun getInstance(imageResId: Int): ScVipSlideshowVpFrag {

            return ScVipSlideshowVpFrag().apply {
                arguments = Bundle().apply {
                    putInt(IMAGE_ID, imageResId)
                }
            }
        }
    }

    override fun setLayoutId(): Int {
        return R.layout.sc_frag_vip_vp
    }

    override fun onLazyLoad() {
        val imageResId = arguments?.getInt(IMAGE_ID) ?: 0

        mDatabind.scVipVpIv.apply {
            setImageResource(imageResId)
        }

    }

}

三、定义ViewPager2的适配器

使用 FragmentStateAdapter 来创建一个适配器,用于在 ViewPager2 中展示一系列的图片。FragmentStateAdapter 是 ViewPager2 的适配器,用于管理与页面相关的 Fragment。这个适配器在 ViewPager2 中非常实用,因为它可以有效地处理页面的生命周期,并且只在用户滑动到的页面上创建 Fragment。

类定义:定义了一个名为 ScVipSlideshowVpAdapter 的类,它继承自 FragmentStateAdapter。

**1、构造函数:**接收三个参数: fragmentManager:用于管理 Fragment 的生命周期。 lifecycle:用于确保适配器与 Fragment 的生命周期同步。 images:一个 IntArray,包含了要展示的图片资源的ID。

**2、getItemCount():**重写了 FragmentStateAdapter 的 getItemCount() 方法,返回图片数组 images 的大小,即轮播图中页面的数量。

**3、createFragment(position: Int):**重写了 FragmentStateAdapter 的 createFragment() 方法,根据传入的位置 position 创建并返回一个 Fragment。 调用ScVipSlideshowVpFrag 的 Fragment 类,有一个静态方法 getInstance(),用于创建并初始化 Fragment 实例。 这个适配器可以与 ViewPager2 一起使用,来实现顶部轮播图的功能,然后在 Activity 或 Fragment 中设置这个适配器。

Kotlin 复制代码
/**
 * 顶部轮播图适配器
 * */
class ScVipSlideshowVpAdapter(
    fragmentManager: FragmentManager,
    lifecycle:Lifecycle,
    private val images:IntArray

) : FragmentStateAdapter(fragmentManager,lifecycle) {
    override fun getItemCount(): Int = images.size
    override fun createFragment(position: Int): Fragment {
        return ScVipSlideshowVpFrag.getInstance(images[position])
    }

}

四、在fragment/activity中使用ViewPager2

1、初始化数据

先初始化轮播图需要展示的图片数据列表、和ViewPager2的适配器,传入images

Kotlin 复制代码
   //设置轮播图内容
    private val images = intArrayOf(
        R.drawable.sc_png_vip_banner1,
        R.drawable.sc_png_vip_banner2,
        R.drawable.sc_png_vip_banner3,
        R.drawable.sc_png_vip_banner4
    )

    //轮播图Vp适配器
    private val slideshowVpAdapter: ScVipSlideshowVpAdapter by lazy {
        ScVipSlideshowVpAdapter(
            childFragmentManager,
            viewLifecycleOwner.lifecycle,
            images
        )
    }

设置xml中定义的ViewPager2的适配器

Kotlin 复制代码
        mDatabind.scVipSlideshowVp.adapter = slideshowVpAdapter

到此为止就已经可以正常在页面中滑动ViewPager2看到所设置的四张banner图片了,但是还没有设置轮播图的指示器

五、设置指示器

1、导入指示器的图片

导入资源文件作为指示器的图片显示,这里导入的就是最常见的小圆点,选中和非选中的两个图标

2、设置指示器

initDotIndicator是一个初始化圆点指示器的方法,用于配合 ViewPager2 使用,显示当前页面的位置。

以下是代码的详细解释:

**1、获取 ViewPager2 和指示器视图:**通过 mDatabind 获取 ViewPager2 和指示器 LinearLayout 的实例。这里因为项目使用的MVVM框架,所以可以直接获取控件的实例。

**2、获取页面总数:**通过 viewPager.adapter?.itemCount 获取 ViewPager2 中的页面总数,并将其存储在 pageCount 变量中。

**3、记录日志:**使用 AppLogTask 类记录页面总数的日志,直接忽略就好了,调试用的(封装过的)。

4、创建并添加指示器圆点:

  1. 使用循环创建与页面总数相等的 ImageView 实例,每个 ImageView 代表一个圆点。
  2. 设置每个圆点的大小和间距。
  3. 根据圆点的位置设置选中和未选中的图片资源。第一个圆点(i == 0)设置为选中状态的图片,其他圆点设置为未选中状态的图片。
  4. 将每个圆点添加到指示器 LinearLayout 中。

**5、记录日志:**为每个添加的圆点记录日志。直接忽略就好了,调试用的(封装过的)。

6、监听 ViewPager2 页面变化:

  1. 注册 ViewPager2.OnPageChangeCallback 监听器,以便在页面变化时更新指示器状态。
  2. 在 onPageSelected 方法中,根据当前页面的位置更新每个圆点的图片资源,将当前页面对应的圆点设置为选中状态,其他圆点设置为未选中状态。

这段代码实现了一个基本的圆点指示器功能,当用户滑动 ViewPager2 时,指示器会相应地更新,显示当前页面的位置。这是轮播图组件中常用的一种指示器样式,能够直观地告诉用户当前查看的是哪一个页面。

Kotlin 复制代码
    // 初始化圆点指示器
    private fun initDotIndicator() {
        val viewPager = mDatabind.scVipSlideshowVp
        val indicator = mDatabind.scVipIndicator

        // 获取页面总数
        val pageCount = viewPager.adapter?.itemCount ?: 0

        AppLogTask.get().pushEventLog(
            "pageCount",
            "$pageCount"
        )

        // 创建并添加指示器圆点
        for (i in 0 until pageCount) {
            val dot = ImageView(requireContext())
            val size = resources.getDimensionPixelSize(R.dimen.dp_6)
            val params = LinearLayout.LayoutParams(size, size)
            if (i != 0) {
                params.leftMargin = resources.getDimensionPixelSize(R.dimen.dp_6)
            }
            dot.layoutParams = params
            dot.setImageResource(if (i == 0) R.drawable.sc_vip_indicator_selected else R.drawable.sc_vip_indicator_unselected)
            indicator.addView(dot)

            AppLogTask.get().pushEventLog(
                "ScVipFrag", "Added dot at position $i"
            )
        }

        // 监听 ViewPager2 页面变化
        viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                super.onPageSelected(position)
                // 更新指示器状态
                for (i in 0 until indicator.childCount) {
                    (indicator.getChildAt(i) as ImageView).setImageResource(
                        if (i == position) R.drawable.sc_vip_indicator_selected else R.drawable.sc_vip_indicator_unselected
                    )
                }
            }
        })
    }

到此就设置完了,注意一下在xml页面中的布局,有可能会覆盖住指示器,导致设置成功之后却显示不了的情况(因为我第一次设置就遇到了,所以加入了调试代码 )(0_0)

相关推荐
学不会•34 分钟前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
Theodore_10222 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
活宝小娜3 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点3 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow3 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o3 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
----云烟----3 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024064 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā4 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue