Android自定義圓環

import android.content.Context
import android.graphics.*
import android.os.Build
import android.util.AttributeSet
import android.view.View
import androidx.annotation.RequiresApi
import kotlin.math.cos
import kotlin.math.roundToInt
import kotlin.math.sin

class Ring : View {
    //半徑
    private var radius = 0f
    //內部填充圓半徑
    private var radiusInner = 0f
    // 中心點
    private var centerX = 0f
    private var centerY = 0f
    // 開始角度
    private var startAngle = 0f
    var colorAndScore = mutableListOf<Pair<Int, Int>>()
        set(value) {
            field = value
            invalidate()
        }
    /**
     * 扇形的角度集合
     */
    private var sweepAngles = mutableListOf<Float>()
    /**
     * 百分比集合
     */
    private var percents = mutableListOf<Int>()
    private val mPaint = Paint()

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)

    /**
     * 強制高等於寬
     */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(widthMeasureSpec))
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        startAngle = 0f
        radius = (width * 0.5).toFloat()
        radiusInner = (radius * 0.7).toFloat()
        this.centerX = (right - left) / 2f
        this.centerY = (bottom - top) / 2f
        val total = colorAndScore.sumBy { it.second }
        if (total <= 0) {
            initDefualtCircle(canvas)
            initCircle(canvas)
            return
        }
        sweepAngles.clear()
        colorAndScore.forEach {
            sweepAngles.add((it.second * 360.00 / total).roundToInt().toFloat())
            percents.add((it.second * 100.00 / total).roundToInt())
        }
        initArc(canvas)
        initCircle(canvas)
        initText(canvas)
    }

    /**
     * 繪製扇形圖
     * */
    private fun initArc(canvas: Canvas?) {

        // 矩形區域
        val rect = RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius)

        mPaint.isAntiAlias = true

        for (i in colorAndScore.indices) {
            val pair = colorAndScore[i]
            mPaint.color = pair.first
            canvas?.drawArc(rect, startAngle, sweepAngles[i], true, mPaint)
            startAngle += sweepAngles[i]
        }
    }

    /**
     * 繪製百分比文字
     */
    private fun initText(canvas: Canvas?) {
        val paint = Paint()
        paint.color = Color.WHITE
        paint.textSize = (radius - radiusInner) / 2
        sweepAngles.forEachIndexed { index, sweepAngle ->
            val angle = ((sweepAngle / 2) + if (index > 0) {
                sweepAngles.subList(0, index).sum()
            } else {
                0f
            })
            var textX = (centerX + ((radius + radiusInner) / 2f) * cos(angle * Math.PI / 180)).toFloat()
            var textY = (centerY + ((radius + radiusInner) / 2f) * sin(angle * Math.PI / 180)).toFloat()
            val percentText = "${percents[index]}%"
            val widthPercentText = paint.measureText(percentText)
            val rect = Rect()
            paint.getTextBounds(percentText, 0, percentText.length, rect)
            val heightPercentText = rect.height()
            canvas?.drawText(percentText, textX - widthPercentText / 2, textY + heightPercentText / 2, paint)
        }
    }

    /**
     *中心圓
     *
     */
    private fun initCircle(canvas: Canvas?) {
        mPaint.color = Color.parseColor("#ffffff")

        canvas?.drawCircle(centerX, centerY, radiusInner, mPaint)

    }

    /**
     *默認灰色圓
     *
     */
    private fun initDefualtCircle(canvas: Canvas?) {
        mPaint.color = Color.parseColor("#EEEEEE")

        canvas?.drawCircle(centerX, centerY, radius, mPaint)
    }
}

傳入數據總和爲0時顯示灰色圓環
默認圓環
傳入數據總和大於0時顯示配置顏色圓環並顯示百分比

		val colorAndAngle = mutableListOf<Pair<Int, Int>>()
		val mColors = intArrayOf(
                ContextCompat.getColor(this, R.color.text_black),
                ContextCompat.getColor(this, R.color.text_pink),
                ContextCompat.getColor(this, R.color.text_pink_4),
                ContextCompat.getColor(this, R.color.text_gold_1)
        )
        for (i in mColors.indices) {
            val pair = Pair(mColors[i], when (i) {
                0 -> {
                    100
                }
                1 -> {
                    1000
                }
                2 -> {
                    208
                }
                else -> {
                    399
                }
            }.toInt())
            colorAndScore.add(pair)
        }
        ring.colorAndScore = colorAndScore

設置數據後的圓環

參考
https://www.jianshu.com/p/346cbfe2552e
https://blog.csdn.net/li_hlkjl/article/details/73929417

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章