はじめに
すみません、うまくタイトルが思いつかなかったので何がしたいのか詳しく説明すると、
- Aのアニメーションを実行
- Bのアニメーションを実行
- (さらに任意の数のアニメーションを実行)
- 1~3をループ
というのを、CoreAnimationでやりたかったという訳です。
具体的には前回の記事の虹色ボーダーアニメーションに少し手を加えて、
- 虹色のボーダーラインを時計回りのアニメーションで表示
- 描画された虹色ボーダーラインを時計回りに消去
- 1~2のアニメーションをループ
というようにしたいと考えました。
完成図だけ先に載せておきます。
消える方にもアニメーション追加してみた pic.twitter.com/2JKwIQRFS7
— M (@p_x9) April 19, 2021
autoreversesではダメなのか
CoreAnimationにはautoreversesという機能がありますが、これはアニメーションを巻き戻すといった機能です。
そのため、以下のように描画されたボーダラインが反時計回りに消えていく形なので今回目的としたアニメーションとは違いました。
(こっちのアニメーションでもいいやないかと思う方もおられるかもしれませんが、そうするとこの記事の題名からして本末転倒なので許してください。)
本編
では今回実装した手順を説明します。
1. ループさせたい複数のCoreAnimationを作成
本題とズレる部分のコードの詳細についてはここでは避けますが(前回の記事を参考にしてもらえればと思います。)、以下のように繰り返したいアニメーションを作成します。
今回はanimation1についてはアニメーションが完了した時その状態を維持しておいて欲しいので、新たにisRemovedOnCompletion
プロパティをfalseにしています。
//前回作成したアニメーション
let animation1 = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.strokeEnd))
animation1.fromValue = 0.0
animation1.toValue = 1.0
animation1.duration = 1.0
animation1.isRemovedOnCompletion = false
aniamtion1.fillMode = .forwards
//今回新しく作成したアニメーション
let animation2 = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.strokeStart))
animation1.fromValue = 0.0
animation1.toValue = 1.0
animation1.duration = 1.0
2. 2番目以降のアニメーションのbeginTime
を設定
2番目以降に実行したいアニメーションについて、beginTime
を
beginTime = これまでに実行したアニメーションのdurationの合計
となるように計算して設定します。
今回は、animation1のdurationが1なので以下のようになります。
animation2.beginTime = 1
もし仮にanimation3があったとすると、animation1とanimation2のdurationの合計を設定する必要があるので、
animation3.beginTime = 2
となります。
3.CAAnimationGroup
でアニメーションをグループ化
以下のようにアニメーションをグループ化します。durationには実行したいアニメーションのdurationの合計を設定します。
let group = CAAnimationGroup()
group.duration = 2.0
group.repeatCount = .infinity
group.animations = [animation1,animation2]
4.グループ化したアニメーションを目的のレイヤに追加
self.shapeLayer.add(group, forKey: "animation-group")
5.完了
これで正しく動くと思います。
timingFunction
以下のように任意のtimingFunctionを設定するとより映えるかもしれません。
group.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
おわりに
読んでいただいてありがとうございました。
ご指摘ご質問等ございましたら、コメントまたはDMまでお願いします。
この記事での内容はこちらのgithubページからダウンロードできます。