38602


iOSアプリの開発において、以下のメソッドを使ってUIViewをアニメーションさせています。

[code]

    UIView.animate(withDuration: 1, delay: 0, options: [], animations: {
        view.center = CGPoint(10, 10) // アニメーションの内容
    }, completion: { _ in
        // アニメーション終了時の処理        
    })
    
[/code]

このようなアニメーションを連続で行いたい場合に、どのように書けばよいでしょうか。  
以下のようにこのメソッドを入れ子にすることで、一応希望の動作を得ることはできましたが、アニメーションの数が増えるにつれてどんどんネストが深くなり、読みにくいコードになってしまい、望ましい書き方ではないような気がしています。

[code]

    // viewの中心座標を(10, 10), (110, 110), (20, 20), (120, 120)の順番に1秒ずつかけて動かす
    UIView.animate(withDuration: 1, delay: 0, options: [], animations: {
        view.center = CGPoint(10, 10)
    }, completion: { _ in
        // 終了時に新しいアニメーションを始める
        UIView.animate(withDuration: 1, delay: 0, options: [], animations: {
            view.center = CGPoint(110, 110)
        }, completion: { _ in
            UIView.animate(withDuration: 1, delay: 0, options: [], animations: {
                view.center = CGPoint(20, 20)
            }, completion: { _ in
                UIView.animate(withDuration: 1, delay: 0, options: [], animations: {
                    view.center = CGPoint(120, 120)
                }, completion: { _ in
                    // 全てのアニメーションが終了
                })
            })
        })
    })
    
[/code]

どのように書くべきか、またはこの書き方をするしかないのか、教えて頂ければ幸いです。  
何卒よろしくお願い申し上げます。


CC BY-SA 3.0
2017-10-10T15:11:58.333
38571
2017-10-11T12:14:53.450
23029
question
swift ios
UIViewのアニメーションを連続で実行させるにはどうすれば良いですか。


連続したアニメーションを実行する別の書き方としてキーフレームアニメーションがあります。  
キーフレームアニメーションのAPIはいくつかありますが、ご提示のコードと同じ動きをさせるには、Core AnimationのAPIを利用します。

Core
Animationでは`UIView`ではなく`CALayer`のプロパティに対してアニメーションを指定するので、`center`の代わりに`position`を使用します。

また、アニメーションと実際のビューの移動は独立しているので、アニメーションが終了した後の位置をあらかじめビューにセットしておく必要があります（そうでなければ、アニメーションが終了したところで元の位置に戻ってしまう）。

どちらが見やすいかは好みだと思います。別にコールバックでネストしていく書き方でも問題ないと思います。

[code]

    view.center = CGPoint(x: 120, y: 120)
    
    let animation = CAKeyframeAnimation(keyPath: "position")
    animation.values = [NSValue(cgPoint: CGPoint(x: 10, y: 10)),
                        NSValue(cgPoint: CGPoint(x: 110, y: 110)),
                        NSValue(cgPoint: CGPoint(x: 20, y: 20)),
                        NSValue(cgPoint: CGPoint(x: 120, y: 120))]
    animation.keyTimes = [0, 0.25, 0.5, 0.75, 1]
    animation.duration = 4
    animation.timingFunctions = [CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut),
                                 CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut),
                                 CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut),
                                 CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut),
                                 CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)]
    view.layer.add(animation, forKey: "")
    
[/code]

キーフレームアニメーションには`UIView`のAPIもあり、同様のコードは下記のようにも書けます。ただし、このAPIはキーフレームごとにアニメーションカーブを設定できず、全体の時間に対するアニメーションカーブになるので、このままでは元のコードの動きとは若干異なります。それが問題なければ、下記の書き方が、標準のAPIでは見やすいと思います。

[code]

    UIView.animateKeyframes(withDuration: 4.0, delay: 0, options: [], animations: {
        UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.25) {
            view.center = CGPoint(x: 10, y: 10)
        }
        UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.25) {
            view.center = CGPoint(x: 110, y: 110)
        }
        UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) {
            view.center = CGPoint(x: 20, y: 20)
        }
        UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) {
            view.center = CGPoint(x: 120, y: 120)
        }
    }, completion: nil)
    
[/code]


CC BY-SA 3.0
2017-10-11T12:14:53.450
38602
2017-10-11T12:14:53.450
5519
38571
answer