[英]Change view on video end in SwiftUI
尝试查找视频的结束时间时出现错误
import SwiftUI
import AVKit
struct ContentViewC: View {
private let player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "videoToPlay", ofType: "mp4")!))
// throw multiple errors
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: .AVPlayerItemDidPlayToEndTime, object: nil)
func playerDidFinishPlaying(note: NSNotification) {
print("video finished")
// how to change view here?
}
var body: some View {
VStack {
AVPlayerControllerRepresented(player: player)
.edgesIgnoringSafeArea(.all)
.onAppear {
player.play()
}
.onDisappear {
player.pause()
player.seek(to: .zero)
}
}
.background(Color(.black))
.edgesIgnoringSafeArea(.all)
}
}
解决后,如何更改 func playerDidFinishPlaying 中的视图?
我的应用程序有这个“HomeView”,它有三个按钮,当点击时,它们导航到一个将播放视频的新视图。 在新视图的视频结束时,我想导航回这个“HomeView”
import SwiftUI
struct ContentView: View {
var body: some View {
let width: CGFloat = 400
let height: CGFloat = 400
let txtWidth: CGFloat = 300
let txtHeight: CGFloat = 100
NavigationView {
ZStack {
Image("app_bg3")
.resizable()
.edgesIgnoringSafeArea(.all)
VStack {
ZStack {
NavigationLink(destination: ContentViewC()) {
HStack(alignment: .bottom) {
Spacer()
VStack {
VStack {
Image("OneCirclePlayBtn")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: width, height: height)
Text("The")
.font(Font.custom("Nunito-Regular", size: 43))
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(Color(.white))
.frame(width: txtWidth, height: txtHeight, alignment: .center)
Text("Voice")
.font(Font.custom("Nunito-Regular", size: 43))
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(Color(.white))
.frame(width: txtWidth, height: txtHeight, alignment: .center)
.offset(y: -50)
}
}
Spacer()
}
}
}.offset(y: 100)
HStack(spacing: 350) {
NavigationLink(destination: ContentViewA()) {
VStack {
VStack {
Image("TwoCirclePlayBtn")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: width, height: height)
Text("The Cast")
.font(Font.custom("Nunito-Regular", size: 33))
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(Color(.white))
.frame(width: txtWidth, height: txtHeight, alignment: .center)
}
}
}
NavigationLink(destination: ContentViewB()) {
VStack {
VStack {
Image("ThreeCirclePlayBtn")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: width, height: height, alignment: .center)
Text("The Artist")
.font(Font.custom("Nunito-Regular", size: 33))
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(Color(.white))
.frame(width: txtWidth, height: txtHeight, alignment: .center)
}
}
}
}.offset(y: -150)
}
}
}.navigationViewStyle(StackNavigationViewStyle())
.accentColor(.white)
.statusBar(hidden: true)
.background(StatusBarHideHelperView())
}
}
class StatusBarHideHelper: UIViewController {
override var prefersStatusBarHidden: Bool { true } // << important !!
}
struct StatusBarHideHelperView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
StatusBarHideHelper()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
}
class PlayerViewModel : ObservableObject {
@Published var videoDone = false
let player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "Early Riser", ofType: "mp4")!))
private var cancellables = Set<AnyCancellable>()
init() {
NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime)
.sink { (_) in
self.videoDone = true
print("Video done")
DispatchQueue.main.async {
self.videoDone = false //reset it on the next run loop
}
}.store(in: &cancellables)
}
}
struct PlayerContentView: View {
@ObservedObject var viewModel = PlayerViewModel()
var body: some View {
VStack {
AVPlayerControllerRepresented(player: viewModel.player)
.edgesIgnoringSafeArea(.all)
.onAppear {
viewModel.player.play()
}
.onDisappear {
viewModel.player.pause()
viewModel.player.seek(to: .zero)
}
if viewModel.videoDone {
NavigationLink(destination: DetailView(), isActive: $viewModel.videoDone) {
EmptyView()
}
}
}
.background(Color(.black))
.edgesIgnoringSafeArea(.all)
}
}
struct DetailView : View {
var body: some View {
Text("Detail")
}
}
struct ContentView: View {
var body: some View {
NavigationView {
PlayerContentView()
}.navigationViewStyle(StackNavigationViewStyle())
}
}
我在这里假设您想使用NavigationView
进行导航,但如果不是这种情况,我可以编辑答案。
这里发生了什么:
我将播放器及其“完成”的 state 移动到一个ObservableObject
——这样,我对如何处理通知有了更多的控制。
收到AVPlayerItemDidPlayToEndTime
通知后,我将videoDone
设置为 true
当videoDone
为 true 时,我在视图层次结构中呈现NavigationLink
,并将isActive
设置为videoDone
请注意,如果您的视图没有嵌入到NavigationView
中(请参阅我的ContentView
),这将不起作用 - 如果NavigationLink
存在于该层次结构之外,它将不会做任何事情。
更新:如果您想返回go 而不是新视图,则使用presentationMode
(与以前相同的PlayerViewModel)可以使用以下方法:
struct PlayerContentView: View {
@ObservedObject var viewModel = PlayerViewModel()
@Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
var body: some View {
VStack {
AVPlayerControllerRepresented(player: viewModel.player)
.edgesIgnoringSafeArea(.all)
.onAppear {
viewModel.player.play()
}
.onDisappear {
viewModel.player.pause()
viewModel.player.seek(to: .zero)
}
}
.background(Color(.black))
.edgesIgnoringSafeArea(.all)
.onReceive(viewModel.$videoDone) { (videoDone) in
if videoDone {
presentationMode.wrappedValue.dismiss()
}
}
}
}
你的观点应该是这样的;
struct PlayerContentView: View {
@State var isVideoPlayed = false
let playerDidFinishNotification = NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime)
private let player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "videoToPlay", ofType: "mp4")!))
var body: some View {
VStack {
AVPlayerControllerRepresented(player: player)
.edgesIgnoringSafeArea(.all)
.onAppear {
player.play()
}
.onDisappear {
player.pause()
player.seek(to: .zero)
}
}
.background(Color(.black))
.edgesIgnoringSafeArea(.all)
.onReceive(playerDidFinishNotification, perform: { _ in
isVideoPlayed = true
NavigationLink("Content View", destination: ContentView(), isActive: $isVideoPlayed)
})
}
}
除了导航链接,您还可以使用、呈现或工作表
ps 你应该用ContentViewC替换PlayerContentView
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.