この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは。きんくまです。
アニメーションのキモはイージング!ということで、今回はカスタムイージングのお話です。
まずはデモを見てください。
これは、左から右に1秒で移動するだけのアニメーションなのですが、1点だけ違いがあって、それはイージングです。
イージングとは?
昔書いた記事があるのですが、時間を等間隔に分割して、その位置を変更すると、アニメーションの動きが全然変わって見えるのです。
UIViewのアニメーションでやりたい
UIViewのアニメーションはこんな感じにやります。
オプションのところが curveEaseIn
のように指定できるのですが種類が少なくてちょっと寂しいところでした。
UIView.animate(withDuration: 1.0,
delay: 0,
options: [.curveEaseIn],
animations: {
}, completion: nil)
UIViewPropertyAnimatorでカスタムイージングを指定できる!
そこでUIViewPropertyAnimatorの登場です。これには、自分で設定したイージングを設定できるのです。すばらしいっ!
今回作ったパラメータ
/// ベジェタイミングタイプ
///
/// オリジナルパラメータ
/// https://github.com/zz85/cubic-bezier-approximations
enum CubicTimingParametersType {
case quadIn
case quadOut
case quadInOut
case cubicIn
case cubicOut
case cubicInOut
case quartIn
case quartOut
case quartInOut
case quintIn
case quintOut
case quintInOut
case sineIn
case sineOut
case sineInOut
case expoIn
case expoOut
case expoInOut
case circIn
case circOut
case circInOut
var controlPointData: [CGFloat] {
switch self {
case .quadIn: return [ 0.26, 0, 0.6, 0.2 ]
case .quadOut: return [ 0.4, 0.8, 0.74, 1 ]
case .quadInOut: return [ 0.48, 0.04, 0.52, 0.96 ]
case .cubicIn: return [ 0.4, 0, 0.68, 0.06 ]
case .cubicOut: return [ 0.32, 0.94, 0.6, 1 ]
case .cubicInOut: return [ 0.66, 0, 0.34, 1 ]
case .quartIn: return [ 0.52, 0, 0.74, 0 ]
case .quartOut: return [ 0.26, 1, 0.48, 1 ]
case .quartInOut: return [ 0.76, 0, 0.24, 1 ]
case .quintIn: return [ 0.64, 0, 0.78, 0 ]
case .quintOut: return [ 0.22, 1, 0.36, 1 ]
case .quintInOut: return [ 0.84, 0, 0.16, 1 ]
case .sineIn: return [ 0.32, 0, 0.6, 0.36 ]
case .sineOut: return [ 0.4, 0.64, 0.68, 1 ]
case .sineInOut: return [ 0.36, 0, 0.64, 1 ]
case .expoIn: return [ 0.66, 0, 0.86, 0 ]
case .expoOut: return [ 0.14, 1, 0.34, 1 ]
case .expoInOut: return [ 0.9, 0, 0.1, 1 ]
case .circIn: return [ 0.54, 0, 1, 0.44 ]
case .circOut: return [ 0, 0.56, 0.46, 1 ]
case .circInOut: return [ 0.88, 0.14, 0.12, 0.86 ]
}
}
}
/// UICubicTimingParametersを作成する
class CubicTimingParametersCreator {
static func createParameters(timingType: CubicTimingParametersType) -> UICubicTimingParameters {
let pointData = timingType.controlPointData
if pointData.count != 4 {
fatalError("the count of pointData must be 4")
}
let pt1 = CGPoint(x: pointData[0], y: pointData[1])
let pt2 = CGPoint(x: pointData[2], y: pointData[3])
return UICubicTimingParameters(controlPoint1: pt1, controlPoint2: pt2)
}
}
これを使ってみます。
//UIViewPropertyAnimatorをイージングを指定して作成!
let params = CubicTimingParametersCreator.createParameters(timingType: timingCurve)
let animator = UIViewPropertyAnimator(duration: 1.0, timingParameters: params)
//アニメーションの内容
let halfSquareW = squareWidth / 2
let centerY = squareY + halfSquareW
animationSquare.center = CGPoint(x: halfSquareW, y: centerY)
animator.addAnimations { [weak self] in
guard let self = self else { return }
let screenW = UIScreen.main.bounds.width
self.animationSquare.center = CGPoint(x: screenW - halfSquareW, y: centerY)
}
propertyAnimator = animator
//スタート
animator.startAnimation()
作ったリポジトリ
cm-tsmaeda/CubicVezierCurveSample
こんな感じにUIViewのアニメーションにもカスタムイージングが指定してできて嬉しい!という話でした。
余談
UIViewPropertyAnimatorで指定できるようになる前にも、カスタムイージングを使ってアニメーションすることができました。
ただ、それはCALayerに対してだけでした。
それで以前、それ用のクラスを書いたこともありました。
KinkumaDesign/CustomMediaTimingFunction
今回作ったイージングのパラメータは、こちらのリポジトリからいただいています。
zz85/cubic-bezier-approximations
その中に私の作ったパラメータが比較対象で載っけてもらっていました。
zz85さんのものは、たぶんプログラム的にコントロールポイントを求めたものだと思うので、私の作ったやつより正確だと思います。(私のは自前のツールを作って手動で値をとったものでしたw)
なので良かったなーと思った次第です。