SwiftUIで全画面表示した動画をドラッグジェスチャーで前画面に戻す説明する。
Swift 5.7 / Xcode 14.0 / iOS 16.0
結論
環境変数dismissを定義してDragGesture()でdismiss()を実行する。
具体例
NavigationLinkから動画を全画面再生し、動画再生画面で下ドラッグするとNavigationViewの親に戻るというAppを作成する。
コード
こちらの記事SwiftUI | Picture in Picture (PiP)のコードをベースとする。
- 環境変数dismissを定義する。
- 動画を全画面表示するためにNavigationBarのBackボタンを非表示にしSafeAreaを無視する設定にする。
- 下にドラッグしたときにdismiss()によりViewを破棄しNavigationBarのBackボタンを表示する。
import SwiftUI
import AVKit
import Combine
let my動画 = AVModel(title: "地球の動画",
url: Bundle.main.url(forResource: "earth",
withExtension: "mp4")!)
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink("▶ 動画を視聴する", destination: 動画ビュー(動画: my動画))
}
}
}
struct 動画ビュー: View {
@Environment(\.dismiss) private var dismiss // ? 1
@State var backButtonHidden: Bool = true
@StateObject private var viewModel = AVViewModel()
let 動画: AVModel
var body: some View {
AVView(avViewModel: viewModel)
.onAppear {
viewModel.avModel = 動画
viewModel.player.play()
}
.navigationBarBackButtonHidden(backButtonHidden) // ? 2
.edgesIgnoringSafeArea(.all) // ? 2
.gesture(
DragGesture()
.onEnded { value in
if value.translation.height > 10 {
viewModel.player.pause()
dismiss() // ? 3
backButtonHidden = false // ? 3
}
}
)
}
}
// View
struct AVView: UIViewControllerRepresentable {
@ObservedObject var avViewModel: AVViewModel
func makeUIViewController(context: Context) -> AVPlayerViewController {
let vc = AVPlayerViewController()
vc.player = avViewModel.player
vc.canStartPictureInPictureAutomaticallyFromInline = true
return vc
}
func updateUIViewController(_ uiViewController: AVPlayerViewController,
context: Context) { }
}
// ViewModel
class AVViewModel: ObservableObject {
@Published var avModel: AVModel?
let player = AVPlayer()
private var cancellable: AnyCancellable?
init() {
setAudioSessionCategoryToPlayback()
cancellable = $avModel.sink(receiveValue: {
guard let model = $0 else { return }
self.player.replaceCurrentItem(with: AVPlayerItem(url: model.url))
})
}
func setAudioSessionCategoryToPlayback() {
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.playback)
} catch {
print("Setting category to AVAudioSessionCategoryPlayback failed.")
}
}
}
// Model
struct AVModel {
let title: String
let url: URL
}
まとめ
SwiftUIで全画面表示した動画をドラッグジェスチャーで前画面に戻す説明した。
コメント