UIKitを使ったアニメーションでカスタマイズしたイージングを使う方法がわかったので共有です。色々調べた結果、UIView.animateくらい簡単にカスタムイージングを設定することができました。
イージングとは...
アニメーションの緩急のこと。これを調整することで、ぬるっとしたアニメーションなどを実現させることができます。
世界一わかりやすい「イージング」と、その応用|ritar|noteとかがわかりやすいと思います。
イージングの調整は、3次ベジェ曲線でパラメータを指定します。(他の指定方法を知らないだけかもしれません...)
3次ベジェ曲線とイージングの関係や調整はcubic-bezier.comで色々試してみると理解しやすいと思います。
UIView.animateでのイージング
iOSでのアニメーションといえばUIView.animateがとてもお手軽です。イージングは options:
引数で指定できるのですが、規定のもの(.curveLinear
, .curveEaseIn
, .curveEaseOut
, .curveEaseInOut
)しか使うことができません。
UIView.animate(withDuration: 1.0, delay: 0, options: .curveLinear) {
linearConstraint.constant = 288
liveView.layoutIfNeeded()
}
カスタマイズしたイージングを使おうと思うと、CoreAnimationのCAMediaTimingFunctionなどを使うことになるのかなと思っていたのですが、UIViewPropertyAnimatorを使えば、UIKitの世界だけでとても簡単に実現できました。
UIViewPropertyAnimatorでのイージング
UIViewPropertyAnimator(duration: 1.0,
controlPoint1: .init(x: 0.2, y: 1),
controlPoint2: .init(x: 1, y: 0.2)) {
customEasingConstraint.constant = 288
liveView.layoutIfNeeded()
}.startAnimation()
UIView.animateとそれほど変わらないコード量で実装できました 🎉
コードを解説しておくと以下の通りとなります。
UIViewPropertyAnimator() の引数 |
説明 |
---|---|
duration: |
アニメーション秒数。UIView.animate のwithDuration: と同じ。 |
controlPoint1 ,controlPoint2
|
イージングの設定。3次ベジェ曲線の制御点を指定する。 上の例では途中で止まるような極端な例にしています。 c.f. https://cubic-bezier.com/#0,1,1,0 |
animations: (上の例ではtrailingClosure) |
UIView.animate のanimations: と同じ。 |
UIViewPropertyAnimatorをインスタンス化して、 startAnimation()
でアニメーションを開始できます。
Demo
- 青:UIView.animateのoption指定なし(デフォルトで
.curveEaseInOut
が適用される) - 赤:UIView.animateのoption:
.curveLinear
- 緑:UIViewPropertyAnimator
アニメーションGIFなのでわかりにくいかもですが、緑のバーは途中で止まって再開するようなイージングになっています。
Demoコード
Demoに使ったコードの全体です。Playgroundで実行できる形になってますので、ぜひ動かしてみてください。
import UIKit
import PlaygroundSupport
// レイアウト準備
let frame = CGRect(x: 0, y: 0, width: 320, height: 320)
let liveView = UIView(frame: frame)
liveView.backgroundColor = .white
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .leading
stackView.spacing = 8
liveView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: liveView.leadingAnchor,
constant: 16),
stackView.centerYAnchor.constraint(equalTo: liveView.centerYAnchor)
])
let animateView = UIView()
animateView.backgroundColor = .blue
let linearView = UIView()
linearView.backgroundColor = .red
let customEasingView = UIView()
customEasingView.backgroundColor = .green
[animateView, linearView, customEasingView].forEach {
stackView.addArrangedSubview($0)
}
let animateConstraint = animateView.widthAnchor.constraint(equalToConstant: 0)
let linearConstraint = linearView.widthAnchor.constraint(equalToConstant: 0)
let customEasingConstraint = customEasingView.widthAnchor.constraint(equalToConstant: 0)
NSLayoutConstraint.activate([
animateConstraint,
animateView.heightAnchor.constraint(equalToConstant: 32),
linearConstraint,
linearView.heightAnchor.constraint(equalToConstant: 32),
customEasingConstraint,
customEasingView.heightAnchor.constraint(equalToConstant: 32)
])
liveView.layoutIfNeeded()
// アニメーション
UIView.animate(withDuration: 1.0) {
animateConstraint.constant = 288
liveView.layoutIfNeeded()
}
UIView.animate(withDuration: 1.0, delay: 0, options: .curveLinear) {
linearConstraint.constant = 288
liveView.layoutIfNeeded()
}
UIViewPropertyAnimator(duration: 1.0,
controlPoint1: .init(x: 0.2, y: 1),
controlPoint2: .init(x: 1, y: 0.2)) {
customEasingConstraint.constant = 288
liveView.layoutIfNeeded()
}.startAnimation()
// Playground準備
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = liveView
completionもつけれる
UIView.animateにも用意されているcompletionもつけることができます。その場合は一度変数で受ける必要があります。
let animator = UIViewPropertyAnimator(duration: 1.0,
controlPoint1: .init(x: 0.2, y: 1),
controlPoint2: .init(x: 1, y: 0.2)) {
customEasingConstraint.constant = 288
liveView.layoutIfNeeded()
}
animator.addCompletion { _ in
customEasingView.backgroundColor = .black
}
animator.startAnimation()
その他にも、一時停止したり、逆再生したり、UIView.animateより複雑なことができるようです(試してない)
もっと使いこなしたい方は UIViewPropertyAnimatorを使いこなそう - Qiita こちらの記事がとても参考になると思います。
まとめ
これで気軽にイージングが試せますね💪
どなたかの助けになれば幸いです🙏