Android で独自の Circular Progress View を作る
この記事は Goodpatch Advent Calendar 2018 の7日目です.
枠が空いていたのでスマブラをしたい気持ちを抑えて少しだけ書くことにします.
目新しいトピックではないので,ご存知の方々は今すぐブラウザを閉じ Switch を起動してください.
概要
独自の Circular Progress を表示するために Custom Drawing View を作った.
環境
- Android SDK 28
- Android Studio 3.4
Custom View の実装方針
Android の View には onDraw
メソッドがあります.
このメソッドには Canvas が引数として渡されるので,その Canvas を使って独自 View の描画をすることができます.
おおまかな流れとしては以下のとおりです.
- View を継承した独自クラスを作る
- Paint のインスタンスを作る
onDraw
メソッドをオーバーライドする- Paint のインスタンスと
onDraw
の引数に渡された Canvas を使って View を描画する
- Paint のインスタンスと
手順
View を継承した独自クラスを作る
class CircularProgressView(context: Context, attrs: AttributeSet) : View(context, attrs)
空の独自クラスを定義したら,好きなレイアウト XML に <CircularProgressView>
要素を追記しておきます.
レイアウトエディタで表示がエラーになるかもしれませんが,ビルドをすればなおります.
Paint のインスタンスをつくる
Canvas に描画するためには,まず Paint のインスタンスを作ります.この Paint のインスタンスで描画の色やアンチエイリアシングの設定などをしていきます.(そして今回いちばん重要な strokeCap
を設定する!!)
class CircularProgressView(context: Context, attrs: AttributeSet) : View(context, attrs) {
private val paint = Paint()
init {
paint.apply {
this.color = Color.rgb(43, 112, 196)
this.style = Paint.Style.STROKE
this.strokeWidth = circleStrokeWidth
this.strokeCap = Paint.Cap.ROUND
this.isAntiAlias = true
}
}
}
onDraw メソッドをオーバーライドする
Paint のインスタンスが用意できたので, onDraw
メソッドで Canvas に描画していきます.
class CircularProgressView(context: Context, attrs: AttributeSet) : View(context, attrs) {
private val paint = Paint()
private val circleBounds = RectF()
private val circleStrokeWidth = 12.0f
// Prevent the edge of the circle is cut out by the view rect.
private val edgePadding = 4.0f
var progressRate = 0.0f
set(value) {
field = MathUtils.clamp(value, 0.0f, 1.0f)
invalidate()
}
init {
paint.apply {
// ...
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas ?: return
val size = min(width, height).toFloat()
val padding = circleStrokeWidth * 0.5f + edgePadding
circleBounds.set(padding, padding, size - padding, size - padding)
val arcStartAngle = 270f
val arcSweepAngle = 360f * progressRate
canvas.drawArc(circleBounds, arcStartAngle, arcSweepAngle, false, paint)
}
}
小さなポイントですが,円弧の外側に padding
を設定しています.
Paint の strokeWidth を増やすと,線の太さが大きくなった分だけ外側にはみ出てしまうためです.
また,円弧の padding
がギリギリだと View の矩形領域と接する部分が切れて潰れてしまうため,少しだけ padding
を追加しています.
これで,Custom Drawing View を使って独自の Circular Progress を表示することができました.
Next Steps
要点を絞るためにここでは説明しませんでしたが,実際に View を使っていくと上記のソースでは不便なところが残っています.例えば以下のようなものでしょうか.
circleStrokeWidth
を変えたいpaint.color
を変えたい- …というのをレイアウト XML で指定したい!!
これらは attrs.xml
にプロパティを定義することで実現できるようになります.詳しくは Creating a View Class | Android Developers にあります.
[コラム] ProgressBar ではダメだったのか?
確かに Android SDK 標準の ProgressBar でもかなり近いものはできるのですが,1点だけ, Bar に丸みを持たせることができませんでした.
独自 View で描画すれば,こういった細かいデザインも再現することができます.今回は Paint の strokeCap
を設定しました.
まとめ・感想
- 独自の Circular Progress を表示するために Custom Drawing View を作った
- View を継承して独自クラスを作った
- Paint に描画の設定をした
- Paint と Canvas を使って描画した
- 標準 ProgressBar の範囲では手の届かないかゆいところに対応できた
Goodpatch ではみんなで楽しくスマブラをしています細部までこだわったアプリを作っています.
Custom View は特に目新しいトピックではないのですが,細部へのこだわりが少しでも伝わればうれしいです.