SwiftUIでLottieのAnimationViewを使う

はじめに

SwiftUIは始めた手でしたがUIViewRepresentable使えば良いということを知っていたので簡単にできると思っていたんですが、そのままだとうまくいかなかったのでメモとして残します。

SwiftUI側の問題のような気がするんですが、bodyの中で定義してframeを指定した時にmakeUIViewでそのままAnimationViewを渡しているとサイズ指定が効かなくなります。

ダメな例

当初以下のコードのようにLottieのAnimationViewを移行させました。

ググって一番上に日本語で出る記事を流用したものでしたがこちらのコードだと問題が発生します。
このままだとサイズ指定ができず画面幅いっぱいになってしまいサイズ指定をしてもLottieAnimationViewのサイズが変わりません。

import SwiftUI
import Lottie

struct LottieAnimationView: UIViewRepresentable {
    let name: String
    let loopMode: LottieLoopMode
    
    func makeUIView(context: Context) -> AnimationView {
        let view = AnimationView(name: name, bundle: Bundle.main)
        view.isUserInteractionEnabled = false
        view.loopMode = loopMode
        view.play()

        return view
    }

    func updateUIView(_ uiView: AnimationView, context: Context) {}
}

struct ContentView: View {
    var body: some View {
        LottieAnimationView(name: "animation-name", loopMode: .loop)
            .frame(width: 250, height: 250)
    }
}

正しい例

はっきりとした理由はわかっていないんですが、以下のようにViewを噛ませる形で作ってやることでSwiftUI上でのframe指定が効くようになりました。

import SwiftUI
import Lottie

struct LottieAnimationView: UIViewRepresentable {
    let name: String
    let loopMode: LottieLoopMode
    
    var animationView = AnimationView()
    
    func makeUIView(context: UIViewRepresentableContext<LottieAnimationView>) -> UIView {
        let view = UIView(frame: .zero)
        
        animationView.animation = Animation.named(name)
        animationView.contentMode = .scaleAspectFit
        animationView.loopMode = loopMode
        animationView.play()
        
        animationView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(animationView)
        
        NSLayoutConstraint.activate([
            animationView.heightAnchor.constraint(equalTo: view.heightAnchor),
            animationView.widthAnchor.constraint(equalTo: view.widthAnchor)
        ])
        
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {}
}

struct ContentView: View {
    var body: some View {
        LottieAnimationView(name: "animation-name", loopMode: .loop)
            .frame(width: 250, height: 250)
    }
}