ice45571
10/31/2018 - 7:15 AM

ExtensibleIndicator

一个和ViewPage结合使用过的指示器

package com.tictalk.tictalk.core.widget

import android.annotation.TargetApi
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.os.Build
import android.support.v4.view.ViewPager
import android.util.AttributeSet
import android.view.View
import com.tictalk.tk_center.util.toPx

/**
 * @Description: 一个和ViewPage结合使用过的指示器
 * @Author: ice
 * @Date: 2018/10/31 10:48 AM
 *
 * 
 * easy to use !
 *
 * ExtensibleIndicator ei = findViewById(R.id.ei);
 * ei.setUpWith(viewPager);
 *
 * width 和 height 目前没有处理wrap_content情况
 */

class ExtensibleIndicator : View {

    private var mChunkWidth = 30.toPx().toFloat()
    private var mChunkHeight = 5.toPx().toFloat()
    private var mChunkRadius = 2.toPx().toFloat()
    private var mLongerChunkWidth = 55.toPx().toFloat()
    private var mChunkBg = Color.parseColor("#FF2F3042")
    private var mCurChunkBg = Color.parseColor("#FF6970FF")
    private var mSpaceWidth = 10.toPx().toFloat()
    private var mChunkPaint: Paint
    var mChunkCount = 3
        set(value) {
            field = value
            postInvalidate()
        }
    private var mCurChunkPosition = 0
    private var mActiveChunkPosition = 0
    private var mActiveChunkFraction = 0f

    constructor(context: Context?) : this(context, null)

    constructor(context: Context?, attr: AttributeSet?) : this(context, attr, 0)

    constructor(context: Context?, attr: AttributeSet?, defStyleAttr: Int) : super(context, attr, defStyleAttr) {

        setLayerType(View.LAYER_TYPE_SOFTWARE, null)

        mChunkPaint = Paint()
        mChunkPaint.style = Paint.Style.FILL
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        setMeasuredDimension(resolveSize(suggestedMinimumWidth, widthMeasureSpec),
                resolveSize(suggestedMinimumHeight, heightMeasureSpec))
    }

    private fun update(activeChunkPosition: Int, activeChunkFraction: Float) {
        //支持viewPager无限轮滑
        val realIndex = activeChunkPosition % mChunkCount

        mActiveChunkPosition = realIndex
        mActiveChunkFraction = activeChunkFraction

        if (activeChunkFraction == 0f) {
            mCurChunkPosition = realIndex
            mActiveChunkPosition = -1
        }

        postInvalidate()
    }

    @TargetApi(Build.VERSION_CODES.M)
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        var l = 0f
        for (i in 0 until mChunkCount) {

//            "i=$i and l=$l".log()

            var r: Float
            when (i) {
                mCurChunkPosition -> {
                    mChunkPaint.color = mCurChunkBg
                    r = l + mLongerChunkWidth - (mLongerChunkWidth - mChunkWidth) * mActiveChunkFraction
                }
                mActiveChunkPosition -> {
                    mChunkPaint.color = mChunkBg
                    r = l + mChunkWidth + (mLongerChunkWidth - mChunkWidth) * mActiveChunkFraction
                }
                else -> {
                    mChunkPaint.color = mChunkBg
                    r = l + mChunkWidth
                }
            }
            canvas.drawRoundRect(l, 0f, r, mChunkHeight, mChunkRadius, mChunkRadius, mChunkPaint)
            l = r

            if (i != mChunkCount - 1) {
                r = l + mSpaceWidth
                mChunkPaint.color = Color.TRANSPARENT
                canvas.drawRect(l, 0f, l + mSpaceWidth, 1f, mChunkPaint)
                l = r
            }

        }

    }

    fun setUpWith(viewPager: ViewPager, chunkCount: Int = mChunkCount) {
        if (chunkCount != mChunkCount) {
            mChunkCount = chunkCount
        }
        viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            private var changeSelectedPosition: Boolean = false
            var isScrolling = false
            var curActiviePosition = 0
            var curScrollState = 0

            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
                if (positionOffset > 0 && positionOffset < 1) {
                    if (curScrollState == ViewPager.SCROLL_STATE_SETTLING && changeSelectedPosition) {
                        //回弹和切换都会经过SCROLL_STATE_SETTLING状态,使用changeSelectedPosition判断是不是回弹
                        return
                    }

                    if (!isScrolling) {
                        isScrolling = true
                        curActiviePosition = if (positionOffset > 0.5) {
                            //开始右滑
                            position
                        } else {
                            //开始左滑
                            position + 1
                        }
                    }

                    val activeChunkFraction: Float = if (curActiviePosition == position) {
                        //右滑
                        1 - positionOffset
                    } else {
                        //左滑
                        positionOffset
                    }
                    changeSelectedPosition = false
                    update(curActiviePosition, activeChunkFraction)
                }
            }

            override fun onPageSelected(position: Int) {
                changeSelectedPosition = true
                update(position, 0f)
            }

            override fun onPageScrollStateChanged(state: Int) {
                curScrollState = state
                if (state == ViewPager.SCROLL_STATE_IDLE) {
                    isScrolling = false
                }
            }

        })
    }
}