close

寫程式久了, 一定會碰到官方提供的view不夠, 需要自己客製化View的時候

最簡單的就是button啊 switch啊 textview等小東西font 或著 style 調整, 

但若有點複雜怎麼辦, 最直接最快的方式就是去找library, 感覺就使用了黑科技一般, 一個瞬間就搞定

但要更改的時候, 卻會麻煩的要死, 問題多多...

這邊來介紹create widget 啊

身為Android 開發人員, 這部分一定要懂的拉

 

圓形progress  其實概念很簡單

就是在view 上面畫兩個東西

1 背景的環

2. progress 的線段

若要額外顯示 progress value 則再加個 text

若是新手看這篇的話,應該會有很多物件疑問。若看不懂的話,就自己再去查吧XD

 

這裡已算是客製化view的範疇

提個基本概念,若要在view中呈現任何東西的話,一定要在onDraw中把東西出來。

這時一定會用到

Canvas: 畫布

Paint: 畫筆

這兩個相關用法,這裡只提相關的,其他請自行爬文去

不囉說,先放成果圖

 

 

RingProgress View 

首先建立一個 可以放在layout中的 custom view 

class RingProgressBar @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    ...
}

@JvmOverloads 是kotlin 給java 多載的方法

可當作

class RingProgressBar : View {
    constructor(context: Context)
    constructor(context: Context, attrs: AttributeSet)
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int)
    ...
}

Init Paint

我們需要三個paint , 分別代表 

Text Paint (textPaint) 

RingBackground Paint(bgPaint)

Progress paint (paint)

    private val textPaint = Paint().apply {
        this.isAntiAlias = true
        style = Paint.Style.FILL
    }
    private val paint: Paint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.STROKE
        strokeCap = Paint.Cap.ROUND
    }
    private val bgPaint: Paint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.STROKE
        strokeCap = Paint.Cap.ROUND
    }

Paint.Style.STROKE : 只畫邊框,沒有填滿

isAntiAlias:防鋸齒

strokeCap: 筆頭樣式, 設為圓頭

paint color 與 strokewidth (筆頭的寬?) 請自行定義

 

Get layour width and height

onSizeChanged中 便可取得layout改變得值 (ex:swithc Portrait / Landscape )

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        Log.d("RingProgressBar", "onSizeChanged")
        centerW = w / 2f
        centerH = h / 2f
        radius = min(centerW, centerH) - radiusOffset

        rectF.apply {
            left = radiusOffset
            top = h / 2 - radius
            right = w - radiusOffset
            bottom = h / 2 + radius
        }
    }

 

rectF 為 RectF物件,用來方便紀錄範圍

 

onDraw

Progress 以逆時鐘方式長出, 所以 startArc 為 (1 - progressValue.toFloat() / max) * 359f

若想要順時鐘長出改為  startArc 為 (progressValue.toFloat() / max) * 359f, 並在起時位置設為 270

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        Log.d("RingProgressBar", "onDraw")

        with(canvas) {
            // add bg
            drawCircle(centerW, centerH, radius, bgPaint)

            // progress
            val startArc = (1 - progressValue.toFloat() / max) * 359f
            drawArc(rectF, 270f + startArc, 359f - startArc, false, paint)

            // progress text
            val text = "$progressValue%"
            textPaint.getTextBounds(text, 0, text.length, textRect)
            val posX = width / 2 - textRect.width() / 2f - textRect.left
            val posY = height / 2 - textRect.height() / 2f - textRect.top
            drawText(text, posX, posY, textPaint)
        }
    }

 

drawCircle 畫出 背景圓環

drawArc 畫出 progress 線段

drawText 畫出文字

 

範例 link : https://gitlab.com/jc7003/ringprogress

本範例使用 attr 方式,便可在layout中定義相關 attr 自定義 可看這篇 View Attribute

 



 

arrow
arrow

    Owen Chen 發表在 痞客邦 留言(1) 人氣()