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

  • coveronMeasureMethod 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
  • coveronDrawMethod, 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
  • setUpMethod implementationViewPagerandIndicatorThe 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