SwiftUI で動画を再生する

もう3月なのに雪が降ってびっくり。亀山です。

SwiftUI で作っているアプリにチュートリアル動画を組み込むために動画を再生する簡単な View を実装しました。よく使いそうなので本記事でシェアします。

ところで、X を便利に使うためのアプリを実験的に開発中です。こちらの Discord でベータ版を配布していますので、ぜひご利用ください。

discord.gg

VideoPlayer

VideoPlayer を使うと、再生ボタンなどが組み込まれた View を作ることができます。動画は AVPlayer クラスで Bundle から取得することで、アプリに組み込んだファイルを再生するようにします。

import SwiftUI
import AVKit

struct TutorialVideoPlayer: View {
    @State var player = AVPlayer(url: Bundle.main.url(forResource: "tutorial",
                                                      withExtension: "mp4")!)
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VideoPlayer(player: player)
            .onAppear {
                player.play()
            }
            .background(Color.black, ignoresSafeAreaEdges: .all)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button {
                        dismiss()
                    } label: {
                        Image(systemName: "xmark")
                    }
                }
            }
            .navigationTitle("使い方")
            .navigationBarTitleDisplayMode(.inline)
            .onReceive(NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime, object: player.currentItem), perform: { _ in
                dismiss()
            })
    }
}

#Preview {
    NavigationStack {
        TutorialVideoPlayer()
    }
}

動画の自動再生

View 表示時に動画を自動的に再生するため、onAppear で次の処理を行います。

.onAppear {
    player.play()
}

動画終了時に閉じる

AVPlayerItem の通知を受け取って、View を閉じます。

.onReceive(NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime, object: player.currentItem), perform: { _ in
    dismiss()
})

表示

次のようにして表示を行います。すぐ閉じれるように sheet.presentationDetents([.large]) を使って表示していますが、sheet の代わりに fullScreenCover を使うと全画面表示にすることができます。

struct ContentView: View {
    @State private var isShowTutorial = false

    var body: some View {
        List {
            Button("使い方をみる") {
                isShowTutorial = true
            }
        }
        .sheet(isPresented: $isShowTutorial) {
            NavigationStack {
                TutorialVideoPlayer()
            }.presentationDetents([.large])
        }
    }
}