高仿知乎日报无限轮播图+指示符切换动画效果

先放上效果图, 因简书不支持webp格式的图片,如上传gif图片太大而无法显示,可移步掘金GitHub查看动态效果图。

仿知乎日报无限轮播图+指示符切换动画

动画分析

  • 未选中页面对应的指示符宽度小,形状为圆形,选中页面对应的指示符宽度大,形状为椭圆。
  • 当页面A->B,A页面对应的指示符宽度由大->小,B页面对应的指示符宽度由小->大,指示符宽度和颜色随滑动而不断变化。
  • 当从最后一个页面手指向右滑动,页面向左时,最后一个页面对应的指示符宽度由大->小,第一个页面对应的指示符宽度由小->大,其余指示符向右平移,有联动效果。
  • 当从第一个页面手指向左滑动,页面向右时,第一个页面对应的指示符宽度由大->小,最后一个对应的指示符宽度由小->大,其余指示符向左平移,有联动效果。

代码实现

TKBanner

实现无限轮播图功能,默认支持圆点和数字指示符。

仿知乎日报APP轮播图 仿品玩APP轮播图 仿虎嗅APP轮播图

CuteIndicator

自定义View,实现ViewPager页面滑动过程中指示符切换动画效果。

相关属性

属性 说明 默认值
IndicatorColor 未选中页面对应的指示符颜色 Color.GRAY
IndicatorSelectedColor 选中页面对应的指示符颜色 Color.WHITE
IndicatorWidth 未选中页面对应的指示符宽度 5dp
IndicatorSelectedWidth 选中页面对应的指示符宽度 20dp
IndicatorHeight 指示符高度 5dp
IndicatorMargin 指示符之间的间隔 5dp
IndicatorShowAnimation 是否显示指示符切换动画 true

关键代码

  • 覆盖onMeasure方法,计算设置指示符宽度和高度。目前没有根据测量模式去判断计算,简单的计算指示符总宽度=(指示符数量-1)*(未选中指示符宽度+指示符之间的间隔)+选中指示符的宽度,此处还有很多优化空间。
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
     super.onMeasure(widthMeasureSpec, heightMeasureSpec)
     if(mIndicatorCount>0) {
        val width = ((mIndicatorCount - 1) * (mIndicatorMargin + mIndicatorWidth) + mIndicatorSelectedWidth).toInt()
        setMeasuredDimension(width, mIndicatorHeight.toInt())
     }
}
  • 覆盖onDraw方法,绘制指示符,针对第一个页面和最后一个页面滑动时特别处理。
override fun onDraw(canvas: Canvas) {
     super.onDraw(canvas)
     if (mIndicatorCount <= 0) {
         return
     }
     var left=0f
     var right=0f
     if (position == (mIndicatorCount - 1) && positionOffset > 0f) {
         for (i in 0 until mIndicatorCount) {
           if(i==0){
              left=0f
              right=left+mIndicatorWidth+(mIndicatorSelectedWidth - mIndicatorWidth) * positionOffset
              mIndicatorPaint.color = ColorUtils.blendARGB(mIndicatorColor, mIndicatorSelectedColor, positionOffset)
           }
           else if(i<position){
              right=left+mIndicatorWidth
              mIndicatorPaint.color = mIndicatorColor
           }
           else if(i==position){
              right=i*(mIndicatorWidth+mIndicatorMargin)+mIndicatorSelectedWidth
              mIndicatorPaint.color = ColorUtils.blendARGB(mIndicatorColor, mIndicatorSelectedColor, 1-positionOffset)
           }
           canvas.drawRoundRect(RectF(left, 0f, right, mIndicatorHeight), mIndicatorWidth / 2, mIndicatorWidth / 2, mIndicatorPaint)
           left=right+mIndicatorMargin
        }
     } else {
        for (i in 0 until mIndicatorCount) {
            if (i < position) {
                left = i * (mIndicatorWidth + mIndicatorMargin)
                right = left + mIndicatorWidth
                mIndicatorPaint.color = mIndicatorColor
             } else if (i == position) {
                left = i * (mIndicatorWidth + mIndicatorMargin)
                right = left + mIndicatorWidth + (mIndicatorSelectedWidth - mIndicatorWidth) * (1 - positionOffset)
                    mIndicatorPaint.color = ColorUtils.blendARGB(mIndicatorColor, mIndicatorSelectedColor, 1 - positionOffset)
             } else if (i == (position + 1)) {
                left = (i - 1) * (mIndicatorMargin + mIndicatorWidth) + mIndicatorWidth + (mIndicatorSelectedWidth - mIndicatorWidth) * (1 - positionOffset) + mIndicatorMargin
                right = i * (mIndicatorMargin + mIndicatorWidth) + mIndicatorSelectedWidth
                mIndicatorPaint.color = ColorUtils.blendARGB(mIndicatorColor, mIndicatorSelectedColor, positionOffset)
             } else {
                left = (i - 1) * (mIndicatorWidth + mIndicatorMargin) + (mIndicatorSelectedWidth + mIndicatorMargin)
                right = left + mIndicatorWidth
                mIndicatorPaint.color = mIndicatorColor
             }
             canvas.drawRoundRect(RectF(left, 0f, right, mIndicatorHeight), mIndicatorWidth / 2, mIndicatorWidth / 2, mIndicatorPaint)
        }
    }
}

  • setUp方法实现ViewPagerIndicator绑定
fun setUp(count:Int) {
    mIndicatorCount = count
    requestLayout()
}

GitHub

完整的代码可以在GitHub上获取,喜欢的可以考虑给我点个赞^

https://github.com/kongpf8848/ViewWorld

参考

BGABanner

CuteIndicator

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容