preface
Recently, I took some time to imitate zhihu daily’s infinite rotation graph and indicator switching animation effect _^_, the data comes from Zhihu DAILY API
Animation analysis
- Indicators corresponding to unselected pages are small in width and round in shape, while those corresponding to selected pages are large in width and oval in shape.
- When page A->B, the width of the indicator corresponding to page A changes from large -> small, and the width and color of the indicator corresponding to page B change from small -> large.
- When you swipe right from the last page to the left, the width of the indicator corresponding to the last page changes from large -> small, the width of the indicator corresponding to the first page changes from small -> large, and the rest of the indicators move to the right, which has a linkage effect.
- When you swipe left from the first page and the page faces right, the width of the indicator corresponding to the first page changes from large -> small, the width of the indicator corresponding to the last page changes from small -> large, and the other indicators shift to the left, which has a linkage effect.
Code implementation
TKBanner
Realize infinite round broadcast graph function, the default support dot and number indicator.
Imitation zhihu Daily APP rotation map | Imitation APP rotation map | Tiger-sniffing APP rote map |
---|---|---|
CuteIndicator
Custom View, realize the sliding process of ViewPager page indicator switch animation effect.
Relevant properties
attribute | instructions | The default value |
---|---|---|
IndicatorColor | The corresponding indicator color of the page is not selected | Color.GRAY |
IndicatorSelectedColor | Select the corresponding indicator color for the page | Color.WHITE |
IndicatorWidth | The indicator width for the page is not selected | 5dp |
IndicatorSelectedWidth | Select the corresponding indicator width for the page | 20dp |
IndicatorHeight | Indicator height | 5dp |
IndicatorMargin | The interval between indicators | 5dp |
IndicatorShowAnimation | Whether to display indicator switch animation | true |
The key code
- cover
onMeasure
Method to calculate the setting indicator width and height. Currently, there is no calculation based on the measurement mode. Simply calculate the total indicator width =(number of indicators -1)*(width of unselected indicators + interval between indicators)+ width of selected indicators. There is a lot of room for optimization here.
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())
}
}
Copy the code
- cover
onDraw
Method, draw indicator, special handling for the first and last page when sliding.
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)
}
}
}
Copy the code
setUp
Method implementationViewPager
andIndicator
The binding
fun setUp(count:Int) {
mIndicatorCount = count
requestLayout()
}
Copy the code
GitHub
The full code is available on GitHub, if you like, please give me a like _^_
Github.com/kongpf8848/…
reference
BGABanner
CuteIndicator