寫程式久了, 一定會碰到官方提供的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

