如何在 SwiftUI 中管理 AVPlayer 状态
How to manage AVPlayer state in SwiftUI
我在 SwiftUI 中有一个 URL 的列表。当我点击一个项目时,我会呈现一个全屏视频播放器。我有一个 @EnvironmentObject
来处理一些查看器选项(例如,是否显示时间码)。我还有一个显示和隐藏时间码的开关(我只在这个例子中包含了开关,因为时间码视图无关紧要)但是每次我更改开关时都会再次创建视图,这会重新设置 AVPlayer
。这是有道理的,因为我在视图的初始化程序中创建播放器。
我考虑过创建自己的 ObserveredObject
class 来包含 AVPlayer
但我不确定如何或在哪里初始化它,因为我需要给它一个URL,我只从 CustomPlayerView
的初始化程序中知道。我还考虑过将播放器设置为 @EnvironmentObject
,但初始化我可能不需要的东西似乎很奇怪(如果用户没有点击 URL 来启动播放器)。
请问创建 AVPlayer
交给 AVKit 的 VideoPlayer
的正确方法是什么?这是我的示例代码:
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
private let avPlayer: AVPlayer
init(url: URL) {
avPlayer = AVPlayer(url: url)
}
var body: some View {
HStack {
VideoPlayer(player: avPlayer)
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}
您可以在此处采用多种方法。您可以尝试一下,看看哪一款最适合您。
选项 1:正如您所说,您可以将 avPlayer
包装在新的 ObserveredObject
class
中
class PlayerViewModel: ObservableObject {
@Published var avPlayer: AVPlayer? = nil
}
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
}
@main
struct DemoApp: App {
var playerViewModel = PlayerViewModel()
var viewerOptions = ViewerOptions()
var body: some Scene {
WindowGroup {
CustomPlayerView(url: URL(string: "Your URL here")!)
.environmentObject(playerViewModel)
.environmentObject(viewerOptions)
}
}
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
@EnvironmentObject var playerViewModel: PlayerViewModel
init(url: URL) {
if playerViewModel.avPlayer == nil {
playerViewModel.avPlayer = AVPlayer(url: url)
} else {
playerViewModel.avPlayer?.pause()
playerViewModel.avPlayer?.replaceCurrentItem(with: AVPlayerItem(url: url))
}
}
var body: some View {
HStack {
VideoPlayer(player: playerViewModel.avPlayer)
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}
选项 2:您可以将 avPlayer
添加到您已经存在的 class ViewerOptions
作为可选 属性 然后在需要时初始化它
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
@Published var avPlayer: AVPlayer? = nil
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
init(url: URL) {
if viewerOptions.avPlayer == nil {
viewerOptions.avPlayer = AVPlayer(url: url)
} else {
viewerOptions.avPlayer?.pause()
viewerOptions.avPlayer?.replaceCurrentItem(with: AVPlayerItem(url: url))
}
}
var body: some View {
HStack {
VideoPlayer(player: viewerOptions.avPlayer)
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}
选项 3:使您的 avPlayer
成为一个状态对象,这样它的内存将由系统管理,在您的视图存在之前,它不会重新设置并为您保持活动状态。
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
@State private var avPlayer: AVPlayer
init(url: URL) {
_avPlayer = .init(wrappedValue: AVPlayer(url: url))
}
var body: some View {
HStack {
VideoPlayer(player: avPlayer)
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}
选项 4:在需要时创建您的 avPlayer
对象然后忘记它(不确定这是否是最适合您的方法,但如果您不需要播放器对象来执行自定义操作,那么您可以使用这个选项)
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
private let url: URL
init(url: URL) {
self.url = url
}
var body: some View {
HStack {
VideoPlayer(player: AVPlayer(url: url))
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}
我在 SwiftUI 中有一个 URL 的列表。当我点击一个项目时,我会呈现一个全屏视频播放器。我有一个 @EnvironmentObject
来处理一些查看器选项(例如,是否显示时间码)。我还有一个显示和隐藏时间码的开关(我只在这个例子中包含了开关,因为时间码视图无关紧要)但是每次我更改开关时都会再次创建视图,这会重新设置 AVPlayer
。这是有道理的,因为我在视图的初始化程序中创建播放器。
我考虑过创建自己的 ObserveredObject
class 来包含 AVPlayer
但我不确定如何或在哪里初始化它,因为我需要给它一个URL,我只从 CustomPlayerView
的初始化程序中知道。我还考虑过将播放器设置为 @EnvironmentObject
,但初始化我可能不需要的东西似乎很奇怪(如果用户没有点击 URL 来启动播放器)。
请问创建 AVPlayer
交给 AVKit 的 VideoPlayer
的正确方法是什么?这是我的示例代码:
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
private let avPlayer: AVPlayer
init(url: URL) {
avPlayer = AVPlayer(url: url)
}
var body: some View {
HStack {
VideoPlayer(player: avPlayer)
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}
您可以在此处采用多种方法。您可以尝试一下,看看哪一款最适合您。
选项 1:正如您所说,您可以将 avPlayer
包装在新的 ObserveredObject
class
class PlayerViewModel: ObservableObject {
@Published var avPlayer: AVPlayer? = nil
}
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
}
@main
struct DemoApp: App {
var playerViewModel = PlayerViewModel()
var viewerOptions = ViewerOptions()
var body: some Scene {
WindowGroup {
CustomPlayerView(url: URL(string: "Your URL here")!)
.environmentObject(playerViewModel)
.environmentObject(viewerOptions)
}
}
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
@EnvironmentObject var playerViewModel: PlayerViewModel
init(url: URL) {
if playerViewModel.avPlayer == nil {
playerViewModel.avPlayer = AVPlayer(url: url)
} else {
playerViewModel.avPlayer?.pause()
playerViewModel.avPlayer?.replaceCurrentItem(with: AVPlayerItem(url: url))
}
}
var body: some View {
HStack {
VideoPlayer(player: playerViewModel.avPlayer)
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}
选项 2:您可以将 avPlayer
添加到您已经存在的 class ViewerOptions
作为可选 属性 然后在需要时初始化它
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
@Published var avPlayer: AVPlayer? = nil
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
init(url: URL) {
if viewerOptions.avPlayer == nil {
viewerOptions.avPlayer = AVPlayer(url: url)
} else {
viewerOptions.avPlayer?.pause()
viewerOptions.avPlayer?.replaceCurrentItem(with: AVPlayerItem(url: url))
}
}
var body: some View {
HStack {
VideoPlayer(player: viewerOptions.avPlayer)
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}
选项 3:使您的 avPlayer
成为一个状态对象,这样它的内存将由系统管理,在您的视图存在之前,它不会重新设置并为您保持活动状态。
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
@State private var avPlayer: AVPlayer
init(url: URL) {
_avPlayer = .init(wrappedValue: AVPlayer(url: url))
}
var body: some View {
HStack {
VideoPlayer(player: avPlayer)
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}
选项 4:在需要时创建您的 avPlayer
对象然后忘记它(不确定这是否是最适合您的方法,但如果您不需要播放器对象来执行自定义操作,那么您可以使用这个选项)
class ViewerOptions: ObservableObject {
@Published var showTimecode = false
}
struct CustomPlayerView: View {
@EnvironmentObject var viewerOptions: ViewerOptions
private let url: URL
init(url: URL) {
self.url = url
}
var body: some View {
HStack {
VideoPlayer(player: AVPlayer(url: url))
Toggle(isOn: $viewerOptions.showTimecode) { Text("Show Timecode") }
}
}
}