円型プログレスバーをCAShapeLayerで実装する

App StoreアプリやiTunes Storeアプリなど、iOSのUIで多用されている、ダウンロード中の進行状況を示す円型プログレスバーを作りたい。

circular_progress_bar_goal

はじめCGPathAddArc(path: m: x: y: radius: startAngle: endAngle: clockwise:)を用いて、startAngleendAngleを実直に指定して弧パスを生成し、CAShapeLayer.pathに指定した。

この方法だと、連続的に値が変化する場合は期待値通りの動きをするが、値が離散的に(0.1 > 0.5 > 0.9 > 0.3…のように)変化した場合、以下のように歪な変形アニメーションとなった。

circular_progress_bar_fail

確かに始点パスから終点パスへとなめらかに遷移しており、パス間のアニメーションとしては間違ってはいないのだが。。
適切な実装方針は、パスの再生成ではなく、パスを固定したままCAShapeLayer.strokeEndだけを変化させる、ということであった。

  • layer.pathには正円を指定する
  • progressに応じ、layer.strokeEndを 0~1 の間で変化させる
    (layer.pathの再指定は必要はない)

circular_progress_bar_compare

二つの手法を比べてみた(赤:前者、緑:後者)。後者は離散的な値の変化に対しても、きちんと円に沿ってパスが伸び縮みしているのがわかる。またprogressの変化のたびにパスを生成しなおす必要もないため、性能面でも優れているはずだ。

ソースコードはこちら 👉 GitHub

コメントを残す