iOS
 Computer >> コンピューター >  >> プログラミング >> iOS

iOSアプリで円形のプログレスバーを作成する方法を解説

iOS開発者にとって、円形のプログレスバー(Circular Progress Bar)の作り方を知っていることは非常に重要です。ダウンロード状況や読み込み中の状態、その他進捗を示す場面のほとんどで使われるため、ほぼすべてのアプリで目にするUI要素と言えるでしょう。

初心者のプログラマーにとっては、円形プログレスバーの実装は難しく感じられ、苦戦することも少なくありません。実装方法はいくつかありますが、この記事ではその中でも最もシンプルで簡単な方法を紹介します。

それでは始めましょう。

Step 1:Xcodeプロジェクトの作成

Xcodeを開き、「Single View Application」を選択して、プロジェクト名を「CircularProgress」とします。

今回作成するのは、パーセンテージを表す3つのボタンと1つの円形プログレスビューを持つアプリです。ボタンをタップすると、対応するパーセンテージに応じてプログレスビューが変化します。

Step 2:カスタムクラスの作成

新しいクラスを作成します。「File」→「New」→「File...」→「Cocoa Touch Class」の順に選択し、UIViewクラスを継承した「CircularProgressView」クラスを作成してください。

Step 3:UIの構築

Storyboard上にUIViewを配置し、そのクラスとして「CircularProgressView」を設定します。さらに3つのボタンを追加し、それぞれ「30%」「60%」「95%」という名前を付けましょう。

次に、ViewController.swiftに3つのボタンすべてに対する@IBActionを作成します。

@IBAction func btn95(_ sender: Any) {
}
@IBAction func btn30(_ sender: Any) {
}
@IBAction func btn60(_ sender: Any) {
}

続いて、UIViewに対応する@IBOutletもViewController.swiftに作成します。

@IBOutlet weak var circularProgress: CircularProgressView!

Step 4:レイヤーの定義

CircularProgressView.swift内で、CAShapeLayer型のオブジェクト「progressLyr」と「trackLyr」の2つを作成します。

var progressLyr = CAShapeLayer()
var trackLyr = CAShapeLayer()

Step 5:色プロパティとdidSetの実装

progressLyrとtrackLyrの色を設定するためのプロパティと、didSetメソッドを以下のように記述します。

var progressClr = UIColor.white {
    didSet {
        progressLyr.strokeColor = progressClr.cgColor
    }
}
var trackClr = UIColor.white {
    didSet {
        trackLyr.strokeColor = trackClr.cgColor
    }
}

ここではprogressLyrとtrackLyrのプロパティを設定しています。

didSetはプロパティオブザーバーの一種で、プロパティの値の変化を監視して反応する仕組みです。プロパティオブザーバーは、新しい値が現在の値と同じであっても、値がセットされるたびに呼び出されます。

Step 6:円形パスの生成

makeCircularPath関数を追加し、以下のコードを記述します。

func makeCircularPath() {
    self.backgroundColor = UIColor.clear
    self.layer.cornerRadius = self.frame.size.width/2
    let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width/2, y: frame.size.height/2), radius: (frame.size.width - 1.5)/2, startAngle: CGFloat(-0.5 * .pi), endAngle: CGFloat(1.5 * .pi), clockwise: true)
    trackLyr.path = circlePath.cgPath
    trackLyr.fillColor = UIColor.clear.cgColor
    trackLyr.strokeColor = trackClr.cgColor
    trackLyr.lineWidth = 5.0
    trackLyr.strokeEnd = 1.0
    layer.addSublayer(trackLyr)
    progressLyr.path = circlePath.cgPath
    progressLyr.fillColor = UIColor.clear.cgColor
    progressLyr.strokeColor = progressClr.cgColor
    progressLyr.lineWidth = 10.0
    progressLyr.strokeEnd = 0.0
    layer.addSublayer(progressLyr)
}

この関数では円形のパスを作成し、そのパラメータや動作を定義しています。trackLyr(トラック層)は全体の背景となるリング、progressLyr(プログレス層)は実際の進捗を示すリングです。

Step 7:初期化処理の実装

必要なinit関数を追加します。StoryboardからUIを設計する場合はrequired initを使用し、コードでUIを構築する場合はoverride initを使用します。今回はStoryboardを使うため、required initを採用します。

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    makeCircularPath()
}

Step 8:アニメーション機能の追加

次に、プログレスをアニメーション表示するための関数setProgressWithAnimationを作成し、以下のコードを書きます。

func setProgressWithAnimation(duration: TimeInterval, value: Float) {
    let animation = CABasicAnimation(keyPath: "strokeEnd")
    animation.duration = duration
    animation.fromValue = 0
    animation.toValue = value
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    progressLyr.strokeEnd = CGFloat(value)
    progressLyr.add(animation, forKey: "animateprogress")
}

CircularProgressView.swiftの完成版コード

以上で完了です。CircularProgressView.swiftの最終的なコードは以下のようになります。

import UIKit
class CircularProgressView: UIView {
    var progressLyr = CAShapeLayer()
    var trackLyr = CAShapeLayer()
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        makeCircularPath()
    }
    var progressClr = UIColor.white {
        didSet {
            progressLyr.strokeColor = progressClr.cgColor
        }
    }
    var trackClr = UIColor.white {
        didSet {
            trackLyr.strokeColor = trackClr.cgColor
        }
    }
    func makeCircularPath() {
        self.backgroundColor = UIColor.clear
        self.layer.cornerRadius = self.frame.size.width/2
        let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width/2, y: frame.size.height/2), radius: (frame.size.width - 1.5)/2, startAngle: CGFloat(-0.5 * .pi), endAngle: CGFloat(1.5 * .pi), clockwise: true)
        trackLyr.path = circlePath.cgPath
        trackLyr.fillColor = UIColor.clear.cgColor
        trackLyr.strokeColor = trackClr.cgColor
        trackLyr.lineWidth = 5.0
        trackLyr.strokeEnd = 1.0
        layer.addSublayer(trackLyr)
        progressLyr.path = circlePath.cgPath
        progressLyr.fillColor = UIColor.clear.cgColor
        progressLyr.strokeColor = progressClr.cgColor
        progressLyr.lineWidth = 10.0
        progressLyr.strokeEnd = 0.0
        layer.addSublayer(progressLyr)
    }
    func setProgressWithAnimation(duration: TimeInterval, value: Float) {
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.duration = duration
        animation.fromValue = 0
        animation.toValue = value
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        progressLyr.strokeEnd = CGFloat(value)
        progressLyr.add(animation, forKey: "animateprogress")
    }
}

Step 9:動作確認

ここまでのコードを実行して、問題なく動作するか確認しましょう。ViewController.swiftにはまだ何もコードを追加していないため、UIは表示されますがまだ機能しません。

Step 10:ViewController.swiftへのコード追加

それでは、ViewController.swiftにコードを追加していきましょう。

まずviewDidLoad()に以下の行を記述します。これによりプログレスバーの色が指定されます。

circularProgress.trackClr = UIColor.cyan
circularProgress.progressClr = UIColor.purple

次に、ボタンのアクションに以下のコードを追加します。durationはそれぞれ95%、30%、60%に対応させています。

@IBAction func btn95(_ sender: Any) {
    circularProgress.setProgressWithAnimation(duration: 1.0, value: 0.95)
}
@IBAction func btn30(_ sender: Any) {
    circularProgress.setProgressWithAnimation(duration: 1.0, value: 0.30)
}
@IBAction func btn60(_ sender: Any) {
    circularProgress.setProgressWithAnimation(duration: 1.0, value: 0.60)
}

ボタンの各関数では、値とdurationを引数としてsetProgressWithAnimationを呼び出しています。

ViewController.swiftの完成版コード

最終的に、ViewController.swiftは以下のようになります。

import UIKit
class ViewController: UIViewController {
    @IBOutlet weak var circularProgress: CircularProgressView!
    override func viewDidLoad() {
        super.viewDidLoad()
        circularProgress.trackClr = UIColor.cyan
        circularProgress.progressClr = UIColor.purple
    }
    @IBAction func btn95(_ sender: Any) {
        circularProgress.setProgressWithAnimation(duration: 1.0, value: 0.95)
    }
    @IBAction func btn30(_ sender: Any) {
        circularProgress.setProgressWithAnimation(duration: 1.0, value: 0.30)
    }
    @IBAction func btn60(_ sender: Any) {
        circularProgress.setProgressWithAnimation(duration: 1.0, value: 0.60)
    }
}

まとめ

これですべて完了です。アプリを実行して「30%」「60%」「95%」のいずれかのボタンをタップすると、ビューがアニメーションしながら進捗を表示するのが確認できます。

CAShapeLayerとCABasicAnimationを組み合わせることで、複雑な描画処理を書かずとも滑らかな円形プログレスバーを簡単に実装できることが分かりました。ぜひ自分のアプリにも応用してみてください。

  1. Tkinterでダウンロードプログレスバーを実装する方法を解説

    ファイルのダウンロードや進捗状況の追跡など、外部ソースやファイルとやり取りするアプリケーションを開発する場合、処理の進行状況をユーザーに視覚的に伝えるプログレスバーがあると便利です。Tkinterでプログレスバーを作成するには、tkinter.ttkパッケージに含まれるProgressbarモジュールを使用します。まずProgressbarオブジェクトをインスタンス化し、向き(orientation)をHORIZONTAL(水平方向)に設定します。その後、プログレスバーの値を増加させながら継続的に更新する関数を定義することで、ダウンロードの進捗を表現できます。サンプルコード以下の例では、プログ

  2. iPhone・iPadでショートカットを作成する方法|自動化で毎日の作業を時短しよう

    日々の生活の中で、少しでも時間を節約したいと考えている人は多いはず。だからこそ、日常生活に「自動化」を取り入れることを強くおすすめします。 自動化こそ、テクノロジーがもたらす最大のメリットのひとつです。本来なら3回のタップが必要だった操作を、わずか1回で済ませられるようにしてくれます。これを活用しない手はありませんよね。 iOSデバイスでは、この自動化機能が「ショートカット」と呼ばれています。すでに多くの開発者たちが、日常的なタスクを効率化する優れたショートカットを公開しています。さらに嬉しいことに、作成したショートカットはiCloud経由で他のiOSデバイスとも同期できるのです。