UIPercentDrivenInteractiveTransitionでアニメーションを連続実行する
この記事はQiitaに投稿されたものの転載です。
やたいこと
- ジェスチャに連動させて画面遷移させたい
UIViewControllerAnimatedTransitioning
,UIPercentDrivenInteractiveTransition
使用
- 画面遷移のアニメーションは、1つのアニメーションが終わってから別のアニメーションを実行させたい
UIViewControllerAnimatedTransitioningとUIPercentDrivenInteractiveTransitionの実装サンプルは UIVIew.animate
を1回使って1つのアニメーションをさせるものばかりで意図した動きにならなかったため、他の実装を探しました。
試したこと1: UIVIew.animateのcompletionで次のアニメーション実行
コード
let duration = transitionDuration(using: transitionContext)
UIView.animate(withDuration: duration / 2, delay: 0, animations: {
toViewController.view.alpha = 0.1
}) { (finished) in
UIView.animate(withDuration: duration / 2, delay: 0, options: [], animations: {
toViewController.view.alpha = 1
}) { (finished) in
}
}
結果
画面遷移には1つ目のアニメーションが使われ、画面遷移が終わってから2つめのアニメーションが開始
試したこと2: UIView.animateのdelayで2つめのアニメーションを遅らせる
コード
let duration = transitionDuration(using: transitionContext)
UIView.animate(withDuration: duration / 2, delay: 0, animations: {
toViewController.view.alpha = 0.1
}) { (finished) in
}
UIView.animate(withDuration: duration / 2, delay: duration / 2, options: [], animations: {
toViewController.view.alpha = 1
}) { (finished) in
}
結果
画面遷移開始時は1つめのアニメーションが終わった状態になっており、画面遷移のアニメーションには2つめのアニメーションが使われる
解決策
@kishikawakatsumi さんによるスタック・オーバーフローの回答で、アニメーションを連続指定できる UIView.animateKeyframes
を知りました。
https://ja.stackoverflow.com/questions/38571
これを使うことで思ったとおりの動きになりました。
UIView.animateKeyframes(withDuration: transitionDuration(using: transitionContext), delay: 0, options: [], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
toViewController.view.alpha = 0.1
}
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
toViewController.view.alpha = 1
}
})
注意点
ジェスチャの途中でUIPercentDrivenInteractiveTransitionの finish()
を呼んでもアニメーションが連続で実行されずに最終的な状態へ直接アニメーションしました。
これは update(_:)
を小刻みに呼ぶことで解決しました。
ただ DispatchQueue.main.asyncAfter
であらかじめすべてのupdateをスケジュールすると正確な時間に実行されないのか動きがカクカクになったため、1回updateを行ったら次をスケジュールして実行、という実装に変えたらうまくいきました。
なぜか UIPercentDrivenInteractiveTransition
の .completionCurve
を指定することで解決しました。
環境
Swift 4.2 iOS 12.1