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

前言

最近抽时间仿照完成了知乎日报的无限轮播图和指示符切换动画作用_^_,数据来源于知乎日报API

动画剖析

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

代码完成

TKBanner

完成无限轮播图功能,默许支持圆点和数字指示符。

仿知乎日报APP轮播图 仿品玩APP轮播图 仿虎嗅APP轮播图
banner_zhihu_daily.webp banner_pingwest.webp banner_huxiu.webp

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上获取,喜欢的可以考虑给我点个赞_^_

github.com/kongpf8848/…

参考

BGABanner

CuteIndicator