如何使用ViewPager实现横向带动画的页面指示器
实现横向滑动页面指示器(View系统版)
方案一:自定义View实现完整动画效果
如果现有库满足不了动画需求,直接自定义View是最灵活的方式,以下是针对ViewPager2的实现思路和代码:
1. 自定义IndicatorView代码
import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.util.AttributeSet import android.view.View import androidx.viewpager2.widget.ViewPager2 class HorizontalPagerIndicator @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { // 指示器核心参数 private var indicatorCount = 0 private var currentPosition = 0 private var scrollOffset = 0f // 绘制画笔 private val normalPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.parseColor("#CCCCCC") style = Paint.Style.FILL } private val selectedPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.parseColor("#000000") style = Paint.Style.FILL } // 指示器尺寸配置 private val indicatorRadius = dpToPx(4f) private val selectedIndicatorRadius = dpToPx(6f) private val indicatorSpacing = dpToPx(8f) override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val desiredWidth = (indicatorCount * (indicatorRadius * 2) + (indicatorCount - 1) * indicatorSpacing).toInt() val desiredHeight = (selectedIndicatorRadius * 2).toInt() setMeasuredDimension( resolveSize(desiredWidth, widthMeasureSpec), resolveSize(desiredHeight, heightMeasureSpec) ) } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) if (indicatorCount == 0) return // 绘制普通状态指示器 for (i in 0 until indicatorCount) { val centerX = getIndicatorCenterX(i) canvas.drawCircle(centerX, height / 2f, indicatorRadius, normalPaint) } // 绘制带滑动动画的选中指示器 val selectedCenterX = getIndicatorCenterX(currentPosition) + scrollOffset * (indicatorRadius * 2 + indicatorSpacing) canvas.drawCircle(selectedCenterX, height / 2f, selectedIndicatorRadius, selectedPaint) } // 计算第i个指示器的中心X坐标 private fun getIndicatorCenterX(position: Int): Float { return indicatorRadius + position * (indicatorRadius * 2 + indicatorSpacing) } // 绑定ViewPager2 fun attachToViewPager(viewPager: ViewPager2) { indicatorCount = viewPager.adapter?.itemCount ?: 0 viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageScrolled( position: Int, positionOffset: Float, positionOffsetPixels: Int ) { currentPosition = position scrollOffset = positionOffset invalidate() } override fun onPageSelected(position: Int) { currentPosition = position scrollOffset = 0f invalidate() } override fun onPageScrollStateChanged(state: Int) {} }) requestLayout() } private fun dpToPx(dp: Float): Float { return dp * resources.displayMetrics.density } }
2. 布局中使用
在XML布局里搭配ViewPager2添加该自定义指示器:
<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/viewPager" android:layout_width="match_parent" android:layout_height="200dp"/> <com.yourpackage.HorizontalPagerIndicator android:id="@+id/indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="16dp"/> </LinearLayout>
3. 代码中绑定关联
在Activity/Fragment中完成ViewPager2和指示器的绑定:
val viewPager = findViewById<ViewPager2>(R.id.viewPager) val indicator = findViewById<HorizontalPagerIndicator>(R.id.indicator) viewPager.adapter = YourPagerAdapter() // 替换为你的PagerAdapter实现 indicator.attachToViewPager(viewPager)
方案二:改造现有Android-ViewPagerIndicator库添加动画
如果想继续使用已引入的库,可通过修改源码添加滑动跟随动画:
- 找到库中的
CirclePageIndicator类 - 添加
mScrollOffset变量记录页面滚动的偏移比例 - 在
onPageScrolled回调中更新mScrollOffset = positionOffset,并调用invalidate()触发重绘 - 修改
onDraw方法,计算选中指示器的动态中心坐标:selectedCenterX = mCenters[mCurrentPage] + mScrollOffset * (mRadius * 2 + mSpacing),用该坐标绘制选中圆形,实现跟随滑动的动画效果
内容的提问来源于stack exchange,提问作者Luther
相关产品推荐
相关产品推荐

