iOSでインジケータのようなくるくる回るアニメーションを造る - CGAffineTransform

はじめに

インジケータを自作する方法です。
標準で搭載されているものでも十分事足りるのですが、アプリの色を出したいときにインジケータの演出もこだわりたいですよね。

提供中のTIME HACKERにも自作のインジケータを導入した方ので、以下のキャプチャのようなものを自作しました。

f:id:project-unknown:20181103200007g:plain

今日は、その際のやりかたです。
パラパラ漫画のような作り方でも良いのですが、上記キャプチャを見てもらえばわかるように、一部だけエンドレスに回転させる程度なら、CGAffineTransformを利用します。

CGAffineTransform

CGAffineTransformは、UIViewの拡大・縮小・回転などを実装するのをサポートしています。

これを用いて、回転するUIViewを作ります。

class IndicatorView: UIView {

    @IBOutlet weak var indicatorPin: UIImageView!

    func start() {
        
            UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveLinear, animations: {
                self.indicatorPin.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
                self.indicatorPin.transform = CGAffineTransform.identity
            }, completion: { completed in
                self.start(title: title)
            })
        }
}

indicatorPinに回転したい画像をセットし、startメソッド内の、UIView.animateメソッドを使って回転させます。

animationsの中身は、以下のように指定することで、1周分の回転を指定します。

self.indicatorPin.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
self.indicatorPin.transform = CGAffineTransform.identity

最後のcompletionで自分自身を再帰呼び出し、1周回ったら次の周へ・・・とエンドレスに呼び出しています。

また、途中で止めたい場合は、stop用のメソッドなどを作ると良いかもです。

完成形

上記含めて、自作Indicatorの簡単な完成形です。
outletのところは、xibと接続してください。

class IndicatorView: UIView {

    
    /// Indicatorの動作フラグです
    ///  - true: Indicatorの動作を停止します
    ///  - false: Indicatorの動作を開始します
    var finished = true
    
    @IBOutlet weak var indicatorPin: UIImageView!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        loadNib()
    }
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        loadNib()
    }

    
    /// Indicatorを開始します
    ///
    func start() {
        finished = false
        running()
    }
    
    
    /// Indicator animationを実行します
    func running() {
        if finished == true {
            return
        }
        
        UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveLinear, animations: {
            self.indicatorPin.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
            self.indicatorPin.transform = CGAffineTransform.identity
        }, completion: { completed in
            self.running()
        })
    }
    
    func stop() {
        finished = true
    }

    private func loadNib(){
        let view = Bundle.main.loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as! UIView
        view.frame = self.bounds
        self.addSubview(view)
    }
}

最後に、これを使いたいViewControllerのStoryboard等に設置して、以下のように呼び出すだけです。

{IndicatorViewのインスタンス}.start()
{IndicatorViewのインスタンス}.stop()