高仿知乎日?qǐng)?bào)無(wú)限輪播圖+指示符切換動(dòng)畫效果

先放上效果圖, 因簡(jiǎn)書不支持webp格式的圖片,如上傳gif圖片太大而無(wú)法顯示,可移步掘金GitHub查看動(dòng)態(tài)效果圖。

仿知乎日?qǐng)?bào)無(wú)限輪播圖+指示符切換動(dòng)畫

動(dòng)畫分析

  • 未選中頁(yè)面對(duì)應(yīng)的指示符寬度小,形狀為圓形,選中頁(yè)面對(duì)應(yīng)的指示符寬度大,形狀為橢圓。
  • 當(dāng)頁(yè)面A->B,A頁(yè)面對(duì)應(yīng)的指示符寬度由大->小,B頁(yè)面對(duì)應(yīng)的指示符寬度由小->大,指示符寬度和顏色隨滑動(dòng)而不斷變化。
  • 當(dāng)從最后一個(gè)頁(yè)面手指向右滑動(dòng),頁(yè)面向左時(shí),最后一個(gè)頁(yè)面對(duì)應(yīng)的指示符寬度由大->小,第一個(gè)頁(yè)面對(duì)應(yīng)的指示符寬度由小->大,其余指示符向右平移,有聯(lián)動(dòng)效果。
  • 當(dāng)從第一個(gè)頁(yè)面手指向左滑動(dòng),頁(yè)面向右時(shí),第一個(gè)頁(yè)面對(duì)應(yīng)的指示符寬度由大->小,最后一個(gè)對(duì)應(yīng)的指示符寬度由小->大,其余指示符向左平移,有聯(lián)動(dòng)效果。

代碼實(shí)現(xiàn)

TKBanner

實(shí)現(xiàn)無(wú)限輪播圖功能,默認(rèn)支持圓點(diǎn)和數(shù)字指示符。

仿知乎日?qǐng)?bào)APP輪播圖 仿品玩APP輪播圖 仿虎嗅APP輪播圖

CuteIndicator

自定義View,實(shí)現(xiàn)ViewPager頁(yè)面滑動(dòng)過程中指示符切換動(dòng)畫效果。

相關(guān)屬性

屬性 說明 默認(rèn)值
IndicatorColor 未選中頁(yè)面對(duì)應(yīng)的指示符顏色 Color.GRAY
IndicatorSelectedColor 選中頁(yè)面對(duì)應(yīng)的指示符顏色 Color.WHITE
IndicatorWidth 未選中頁(yè)面對(duì)應(yīng)的指示符寬度 5dp
IndicatorSelectedWidth 選中頁(yè)面對(duì)應(yīng)的指示符寬度 20dp
IndicatorHeight 指示符高度 5dp
IndicatorMargin 指示符之間的間隔 5dp
IndicatorShowAnimation 是否顯示指示符切換動(dòng)畫 true

關(guān)鍵代碼

  • 覆蓋onMeasure方法,計(jì)算設(shè)置指示符寬度和高度。目前沒有根據(jù)測(cè)量模式去判斷計(jì)算,簡(jiǎn)單的計(jì)算指示符總寬度=(指示符數(shù)量-1)*(未選中指示符寬度+指示符之間的間隔)+選中指示符的寬度,此處還有很多優(yōu)化空間。
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方法,繪制指示符,針對(duì)第一個(gè)頁(yè)面和最后一個(gè)頁(yè)面滑動(dòng)時(shí)特別處理。
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方法實(shí)現(xiàn)ViewPagerIndicator綁定
fun setUp(count:Int) {
    mIndicatorCount = count
    requestLayout()
}

GitHub

完整的代碼可以在GitHub上獲取,喜歡的可以考慮給我點(diǎn)個(gè)贊^

https://github.com/kongpf8848/ViewWorld

參考

BGABanner

CuteIndicator

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容