どういうことか
Lottieアニメーションの純正ライブラリを使用している。
詳しいアニメーションをここに貼ることはできないが、例えば背筋をシャキッと伸ばす人間のアニメーションがあるとして、目と口だけが背筋を伸ばした際にズレてしまう、といった挙動が起こっている。
なぜかWebのLottieアニメーションのプレビューやAndroid端末上ではうまく動いている。
何度かデザイナーにJsonを修正してもらったが、挙動が変わることはなかった。
解決した方法
アニメーションのレンダリングエンジンをCoreAnimation(デフォルト)ではなくMainThreadを使用するように指定する。
struct LottieSampleView: UIViewRepresentable {
var name: String
var animationView = LottieAnimationView()
func makeUIView(context: UIViewRepresentableContext<LottieSampleView>) -> UIView {
let view = UIView(frame: .zero)
animationView.animation = LottieAnimation.named(name)
// 該当のjsonの場合のみメインスレッドでレンダリング
if name.contains("senobi") {
animationView.configuration.renderingEngine = .mainThread
}
animationView.play()
// 基本的なレイアウト設定
animationView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(animationView)
NSLayoutConstraint.activate([
animationView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
animationView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
])
return view
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LottieSampleView>) {}
}
ただ、例えば1つの画面にたくさんのアニメーションが混在してる場合に「すべてMainThreadで指定」としてしまうと全体のアニメーションがカクつくという問題が起こる。また、従来のUIや挙動に影響を与えかねないので、できる限りはデフォルトのCoreAnimationを使用するべきだとも考えられる(後述)。
今回は他の手段もいろいろ試してみたが、この方法でしか解決できなかった。
補足
なぜデフォルト(CoreAnimation)ではうまくいかず、MainThreadではうまくいったのか、という推測
- CoreAnimationは非同期で各レイヤーを個別に処理している
- 複雑な親子関係のある変形で同期の問題が発生したのでは?と考えている
- 単純なアニメーションには向いている
- MainThreadは描画処理を同期的に実行している
MainThreadはどういう役割を担っているか
- アプリの通常の操作やUIの描画を担っている
- タップエフェクトなどはCoreAnimationがデフォルトで設定されている
懸念は?
上記理由から通常操作への負荷が増加する可能性はあるが、今回はひとつのアニメーションのみの適用なのでそれほど影響を与えないと考えている。