はじめに

弊社のアプリ開発では、アニメーションの実装にLottieを利用する機会が増えてきました。複雑なアニメーションも手軽に実装でき、マルチプラットフォームでの展開も容易なので、利用されている方も多くいらっしゃるのではないでしょうか。

今回の記事では、UIKitベースで作成されている Lottie SDK を SwiftUI で利用するための手順を紹介してみようと思います。

開発環境

今回の記事は、以下の環境で動作確認を行なっております。

  • macOS 12.0.1
  • iOS 15.0 (simulator)
  • Xcode 13.1

プロジェクト準備

SwiftUIを利用したiOSアプリプロジェクトを新規で作成し、Swift Package Manager 経由で Lottie iOS SDK を組み込みました。

アニメーションファイルを用意

Lottie で利用するアニメーションファイルは、LottieFiles というサイトで入手可能です。会員登録(無料)が必要ですが、数多くのアニメーション素材をダウンロードすることが可能です。

今回はこのサイトからCat Loaderというアニメーション素材を利用させてもらうことにします。右上にあるメニューから Lottie JSON を選択して、jsonファイルをダウンロードしてください。

ダウンロードしたjsonファイルは、任意の名前に変更してXcodeプロジェクトに組み込みます。今回は cat.json というファイル名にしました。

アニメーション用のViewを作成

次に、Lottieのアニメーションファイルを使ったアニメーション用のViewを作成します。UIKitベースのSDKを利用するため、UIViewRepresentableを実装し、以下のように作成しました。

import SwiftUI
import Lottie

struct LottieView: UIViewRepresentable {
    
    func makeUIView(context: Context) -> UIView {
        let view = AnimationView(name: "cat")
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
    }
}

こちらをContentViewから読み込んでみます。

import SwiftUI

struct ContentView: View {
    var body: some View {
        LottieView()
    }
}

表示されましたが、サイズが合っていないのでサイズを調整します。

import SwiftUI

struct ContentView: View {
    var body: some View {
        LottieView()
            .frame(width: 200, height: 200) // サイズを指定.
    }
}

どうやら frame() が効いていないようです。LottieView のサイズは200 * 200になっているのですが、肝心のAnimationViewがLottieViewをはみ出してしまっています。

そのため、LottieViewを以下のように修正します。UIViewを親として用意し、AnimationViewをaddSubView()します。その際に、AutoLayoutで親ビューのサイズに合わせるようにします。

func makeUIView(context: Context) -> UIView {
    let view = AnimationView(name: "cat")
    view.translatesAutoresizingMaskIntoConstraints = false
    
    // 親ビューを用意し、AnimationViewをサブビューにする.
    let parentView = UIView()
    parentView.addSubview(view)
    parentView.addConstraints([
        view.widthAnchor.constraint(equalTo: parentView.widthAnchor),
        view.heightAnchor.constraint(equalTo: parentView.heightAnchor)
    ])
    
    return parentView
}

これで frame() を用いたサイズ指定が可能になりました。

アニメーションさせる

では実際にアニメーションさせてみましょう。LottieViewにアニメーションの状態を管理するプロパティ isPlay を追加し、この状態に合わせてアニメーションのON/OFFを切り替えるようにします。

ContentViewには、この状態を切り替えるためのToggleスイッチを用意しました。

@Binding var isPlay: Bool // アニメーションの状態管理.

func updateUIView(_ uiView: UIView, context: Context) {
    // AnimationViewを取得.
    guard let view = uiView.subviews.compactMap({ $0 as? AnimationView }).first else { return }
    
    if isPlay {
        // すでにアニメーション中なら何もしない.
        if view.isAnimationPlaying { return }
        
        // アニメーション開始.
        view.play { _ in
            // 終わったら状態をOFFにする.
            isPlay = false
        }
    } else {
        // アニメーションを一時停止.
        view.pause()
    }
}
struct ContentView: View {
    
    @State private var isPlay = false // アニメーションの状態管理
    
    var body: some View {
        VStack {
            LottieView(isPlay: $isPlay)
                .frame(width: 200, height: 200)
            Toggle("アニメーション", isOn: $isPlay)
        }
        .padding()
    }
}

ToggleをONにするとアニメーションを開始し、終了するとToggleもOFFになります。アニメーションの途中でToggleを操作することも可能です。

アニメーションをループさせる

次に、アニメーションのループ設定を切り替えられるようにします。ループ設定の状態管理を行うためのBoolプロパティを追加し、Toggleで切り替えられるようにしました。

@Binding var isPlay: Bool // アニメーションの状態管理.
@Binding var isLoop: Bool // ループ設定の状態管理.

func updateUIView(_ uiView: UIView, context: Context) {
    // AnimationViewを取得.
    guard let view = uiView.subviews.compactMap({ $0 as? AnimationView }).first else { return }
    
    // ループ状態によってloopModeを切り替える.
    view.loopMode = isLoop ? .loop : .playOnce
    
    // 省略.
}
struct ContentView: View {
    
    @State private var isPlay = false // アニメーションの状態管理.
    @State private var isLoop = false // ループ設定の状態管理.
    
    var body: some View {
        VStack {
            LottieView(isPlay: $isPlay, isLoop: $isLoop)
                .frame(width: 200, height: 200)
            Toggle("アニメーション", isOn: $isPlay)
            Toggle("ループ", isOn: $isLoop)
        }
        .padding()
    }
}

ループ設定がONの場合はアニメーションを続けるようになりました。ループ設定がOFFの場合は、そのアニメーションが終わったら終了します。

最後に

いかがだったでしょうか。Lottieはやはり優秀なアニメーションライブラリですね。

今後はSwiftUIを利用した開発も少しずつ増えてくるでしょうが、UIKitベースのライブラリもまだまだたくさんあります。こういった使い方を把握し、SwiftUIが盛り上がってくるといいですね!



ギャップロを運営しているアップフロンティア株式会社では、一緒に働いてくれる仲間を随時、募集しています。 興味がある!一緒に働いてみたい!という方は下記よりご応募お待ちしております。
採用情報をみる