SwiftUI 中的 VideoPlayer 在父视图更新时停止播放
VideoPlayer in SwiftUI stops playing when parent-View updates
使用 Swift5.3.2,iOS14.4.1,Xcode 12.4,
我成功地 运行 SwiftUI 中的视频播放器。
我正在使用以下代码调用播放器视图:VideoPlayer(player: AVPlayer(url: url))
。
问题是每当 VideoPlayer 的父视图更新(即重新呈现)时,视频就会停止播放。
由于在 SwiftUI 中我无法控制何时发生这种重新渲染时刻,所以我不知道如何解决这个问题。
有什么想法吗?
这是完整的代码:
VideoPlayer 视图是这样调用的:
struct MediaTabView: View {
@State private var url: URL
var body: some View {
// CALL TO VIDEOPLAYER IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
VideoPlayer(player: AVPlayer(url: url))
}
}
MediaTabView 是这样调用的:
import SwiftUI
struct PageViewiOS: View {
var body: some View {
ZStack {
Color.black
// CALL TO MEDIATABVIEW IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!d
MediaTabView(url: URL(string: "https://someurel.com"))
CloseButtonView()
}
}
}
PageViewiOS 视图是这样调用的:
struct MainView: View {
@EnvironmentObject var someState: AppStateService
var body: some View {
NavigationView {
Group {
if someState = .stateOne {
// CALL TO PAGEVIEWIOS IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
PageViewiOS()
} else {
Text("hello")
}
}
}
}
}
我找到了解决办法。
调用以下内容:
CustomPlayerView(url: url)
...而不是:
VideoPlayer(player: AVPlayer(url: url))
不确定为什么会这样,很难。
也许有人可以进一步解释?
这是 CustomVideoPlayer 代码:
struct CustomPlayerView: View {
private let url: URL
init(url: URL) {
self.url = url
}
var body: some View {
VideoPlayer(player: AVPlayer(url: url))
}
}
通过这个小改动,即使父视图重新呈现,视频也会继续播放。仍然不确定为什么???
------------ 用@jnpdx 的提示回答--------
我进一步更改了 CustomVideoPlayer :
CustomPlayerView(playerViewModel: PlayerViewModel(avPlayer: AVPlayer(url: url)))
import SwiftUI
import AVKit
class PlayerViewModel: ObservableObject {
@Published var avPlayer: AVPlayer
init(avPlayer: AVPlayer) {
self.avPlayer = avPlayer
}
}
struct CustomPlayerView: View {
@StateObject var playerViewModel: PlayerViewModel
var body: some View {
VideoPlayer(player: playerViewModel.avPlayer)
}
}
这是对我们对另一个答案的评论线程的回应:
class PlayerViewModel: ObservableObject {
@Published var avPlayer: AVPlayer?
func loadFromUrl(url: URL) {
avPlayer = AVPlayer(url: url)
}
}
struct CustomPlayerView: View {
var url : URL
@StateObject private var playerViewModel = PlayerViewModel()
var body: some View {
ZStack {
if let avPlayer = playerViewModel.avPlayer {
VideoPlayer(player: avPlayer)
}
}.onAppear {
playerViewModel.loadFromUrl(url: url)
}
}
}
我不确定这是否确实更好,因此值得测试。但是,它确实控制何时创建 AVPlayer
并避免在父级的每个渲染器上重新创建 PlayerViewModel
。
使用@jnpdx 的解决方案,现在一切正常。
这是最终的解决方案(完全归功于@jnpdx):
import SwiftUI
import AVKit
class PlayerViewModel: ObservableObject {
@Published var avPlayer: AVPlayer?
func loadFromUrl(url: URL) {
avPlayer = AVPlayer(url: url)
}
}
struct CustomPlayerView: View {
var url : URL
@StateObject private var playerViewModel = PlayerViewModel()
var body: some View {
ZStack {
if let avPlayer = playerViewModel.avPlayer {
VideoPlayer(player: avPlayer)
}
}.onAppear {
playerViewModel.loadFromUrl(url: url)
}
}
}
有了它,像这样调用 CustomPlayerVideo 就足够了:
CustomPlayerView(url: url)
备注:我需要在我的 CustomPlayerView 中使用 ZStack
而不是 Group
才能正常工作。
使用 Swift5.3.2,iOS14.4.1,Xcode 12.4,
我成功地 运行 SwiftUI 中的视频播放器。
我正在使用以下代码调用播放器视图:VideoPlayer(player: AVPlayer(url: url))
。
问题是每当 VideoPlayer 的父视图更新(即重新呈现)时,视频就会停止播放。
由于在 SwiftUI 中我无法控制何时发生这种重新渲染时刻,所以我不知道如何解决这个问题。
有什么想法吗?
这是完整的代码:
VideoPlayer 视图是这样调用的:
struct MediaTabView: View {
@State private var url: URL
var body: some View {
// CALL TO VIDEOPLAYER IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
VideoPlayer(player: AVPlayer(url: url))
}
}
MediaTabView 是这样调用的:
import SwiftUI
struct PageViewiOS: View {
var body: some View {
ZStack {
Color.black
// CALL TO MEDIATABVIEW IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!d
MediaTabView(url: URL(string: "https://someurel.com"))
CloseButtonView()
}
}
}
PageViewiOS 视图是这样调用的:
struct MainView: View {
@EnvironmentObject var someState: AppStateService
var body: some View {
NavigationView {
Group {
if someState = .stateOne {
// CALL TO PAGEVIEWIOS IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
PageViewiOS()
} else {
Text("hello")
}
}
}
}
}
我找到了解决办法。
调用以下内容:
CustomPlayerView(url: url)
...而不是:
VideoPlayer(player: AVPlayer(url: url))
不确定为什么会这样,很难。
也许有人可以进一步解释?
这是 CustomVideoPlayer 代码:
struct CustomPlayerView: View {
private let url: URL
init(url: URL) {
self.url = url
}
var body: some View {
VideoPlayer(player: AVPlayer(url: url))
}
}
通过这个小改动,即使父视图重新呈现,视频也会继续播放。仍然不确定为什么???
------------ 用@jnpdx 的提示回答--------
我进一步更改了 CustomVideoPlayer :
CustomPlayerView(playerViewModel: PlayerViewModel(avPlayer: AVPlayer(url: url)))
import SwiftUI
import AVKit
class PlayerViewModel: ObservableObject {
@Published var avPlayer: AVPlayer
init(avPlayer: AVPlayer) {
self.avPlayer = avPlayer
}
}
struct CustomPlayerView: View {
@StateObject var playerViewModel: PlayerViewModel
var body: some View {
VideoPlayer(player: playerViewModel.avPlayer)
}
}
这是对我们对另一个答案的评论线程的回应:
class PlayerViewModel: ObservableObject {
@Published var avPlayer: AVPlayer?
func loadFromUrl(url: URL) {
avPlayer = AVPlayer(url: url)
}
}
struct CustomPlayerView: View {
var url : URL
@StateObject private var playerViewModel = PlayerViewModel()
var body: some View {
ZStack {
if let avPlayer = playerViewModel.avPlayer {
VideoPlayer(player: avPlayer)
}
}.onAppear {
playerViewModel.loadFromUrl(url: url)
}
}
}
我不确定这是否确实更好,因此值得测试。但是,它确实控制何时创建 AVPlayer
并避免在父级的每个渲染器上重新创建 PlayerViewModel
。
使用@jnpdx 的解决方案,现在一切正常。
这是最终的解决方案(完全归功于@jnpdx):
import SwiftUI
import AVKit
class PlayerViewModel: ObservableObject {
@Published var avPlayer: AVPlayer?
func loadFromUrl(url: URL) {
avPlayer = AVPlayer(url: url)
}
}
struct CustomPlayerView: View {
var url : URL
@StateObject private var playerViewModel = PlayerViewModel()
var body: some View {
ZStack {
if let avPlayer = playerViewModel.avPlayer {
VideoPlayer(player: avPlayer)
}
}.onAppear {
playerViewModel.loadFromUrl(url: url)
}
}
}
有了它,像这样调用 CustomPlayerVideo 就足够了:
CustomPlayerView(url: url)
备注:我需要在我的 CustomPlayerView 中使用 ZStack
而不是 Group
才能正常工作。