在 Swift 中导航 'back' 时 AVPlayer 视频消失
AVPlayer video disappears when navigating 'back' in Swift
导航到子视图时,我已将其设置为自动播放视频。在视频的底部,有一组指向相关内容的链接。单击其中一个时,一个新视图将被推入堆栈并开始播放另一个视频。
使用自动生成的“<返回”按钮返回上一个视图(有不同的视频)时会出现问题。这个原始视图可以使用播放器控件进行操作,但屏幕上没有任何显示。
我已尝试更新 CGRect 框架,使用 onAppear 重新初始化视频播放器,并遵循了建议 。
到目前为止似乎没有任何效果。这是我用于实际视频播放器的代码(改编自 Chris Mash 的网站):
import SwiftUI
import AVKit
import UIKit
import AVFoundation
let playerLayer = AVPlayerLayer()
class PlayVideo: UIView {
init(frame: CGRect, url: URL) {
super.init(frame: frame)
// Create the video player using the URL passed in.
let player = AVPlayer(url: url)
player.volume = 100 // Will play audio if you don't set to zero
player.play() // Set to play once created
// Add the player to our Player Layer
playerLayer.player = player
playerLayer.videoGravity = .resizeAspectFill // Resizes content to fill whole video layer.
playerLayer.backgroundColor = UIColor.black.cgColor
layer.addSublayer(playerLayer)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}
static func pauseVideo() {
playerLayer.player?.pause()
}
}
struct ViewVideo: UIViewRepresentable {
var videoURL:URL
var previewLength:Double?
func makeUIView(context: Context) -> UIView {
return PlayVideo(frame: .zero, url: videoURL)
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
这是从主视图调用的,使用:
ViewVideo(videoURL: videoURL)
我能想到的唯一解决方法是禁用后退按钮并强制用户每次都返回主视图。这是一个糟糕的选择,我希望有人能在这里提供一些有用的建议。谢谢-
如果我没有理解错的话,当您导航到新视图时,您会播放不同的视频。所以你创建了一个新的 PlayVideo
视图?
那么问题是你的playerLayer
是静态的属性。新视图会将新播放器设置为 playerLayer
并替换旧播放器。同样,如果您暂停一个玩家,则两个玩家都将暂停。此外,将播放器作为子层添加到新视图会将其从旧视图中移除。
您需要 playerLayer
作为本地 属性 来查看。或者至少 AVPlayerLayer
用于您要播放的每个视频。然后,当每个视频可见时,您需要一个 pausing/restarting 机制。例如通过实施 viewWillAppear
。当您导航回视图/视图变为可见时,始终会调用此方法。
感谢@dominik-105 帮助解决这个问题。我能够使用提出的建议解决问题。
具体来说,我删除了 playerLayer 的全局定义,而是将其作为局部变量放在我的主视图调用中:
var playerLayer = AVPlayerLayer()
然后我使用 playerLayer: playerLayer 标签调用 ViewVideo,然后 ViewVideo 使用 playerLayer:AVPlayerLayer 调用 PlayVideo 作为初始化的一部分。
有趣的是,这导致我用来定义视频框大小的覆盖布局功能出现问题。我现在直接在 init 中定义框架并删除旧的覆盖功能代码。完整代码现在是:
import SwiftUI
import AVKit
import UIKit
import AVFoundation
class PlayVideo: UIView {
init(frame: CGRect, url: URL, playerLayer: AVPlayerLayer, width: CGFloat, height: CGFloat) {
super.init(frame: frame)
// Create the video player using the URL passed in.
let player = AVPlayer(url: url)
player.volume = 100 // Will play audio if you don't set to zero
player.play() // Set to play once created
// Add the player to our Player Layer
playerLayer.player = player
playerLayer.videoGravity = .resizeAspectFill // Resizes content to fill whole video layer.
playerLayer.backgroundColor = UIColor.black.cgColor
playerLayer.player?.actionAtItemEnd = .pause
layer.addSublayer(playerLayer)
playerLayer.frame = CGRect(x: 0, y: 0, width: width, height: height)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
struct ViewVideo: UIViewRepresentable {
var videoURL:URL
var playerLayer: AVPlayerLayer
var width: CGFloat
var height: CGFloat
func makeUIView(context: Context) -> UIView {
return PlayVideo(frame: .zero, url: videoURL, playerLayer: playerLayer, width: width, height: height)
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
我使用 GeometryReader 定义框的大小,然后将宽度和高度传递给结构,结构将其传递给 class。
导航到子视图时,我已将其设置为自动播放视频。在视频的底部,有一组指向相关内容的链接。单击其中一个时,一个新视图将被推入堆栈并开始播放另一个视频。
使用自动生成的“<返回”按钮返回上一个视图(有不同的视频)时会出现问题。这个原始视图可以使用播放器控件进行操作,但屏幕上没有任何显示。
我已尝试更新 CGRect 框架,使用 onAppear 重新初始化视频播放器,并遵循了建议
到目前为止似乎没有任何效果。这是我用于实际视频播放器的代码(改编自 Chris Mash 的网站):
import SwiftUI
import AVKit
import UIKit
import AVFoundation
let playerLayer = AVPlayerLayer()
class PlayVideo: UIView {
init(frame: CGRect, url: URL) {
super.init(frame: frame)
// Create the video player using the URL passed in.
let player = AVPlayer(url: url)
player.volume = 100 // Will play audio if you don't set to zero
player.play() // Set to play once created
// Add the player to our Player Layer
playerLayer.player = player
playerLayer.videoGravity = .resizeAspectFill // Resizes content to fill whole video layer.
playerLayer.backgroundColor = UIColor.black.cgColor
layer.addSublayer(playerLayer)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}
static func pauseVideo() {
playerLayer.player?.pause()
}
}
struct ViewVideo: UIViewRepresentable {
var videoURL:URL
var previewLength:Double?
func makeUIView(context: Context) -> UIView {
return PlayVideo(frame: .zero, url: videoURL)
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
这是从主视图调用的,使用: ViewVideo(videoURL: videoURL)
我能想到的唯一解决方法是禁用后退按钮并强制用户每次都返回主视图。这是一个糟糕的选择,我希望有人能在这里提供一些有用的建议。谢谢-
如果我没有理解错的话,当您导航到新视图时,您会播放不同的视频。所以你创建了一个新的 PlayVideo
视图?
那么问题是你的playerLayer
是静态的属性。新视图会将新播放器设置为 playerLayer
并替换旧播放器。同样,如果您暂停一个玩家,则两个玩家都将暂停。此外,将播放器作为子层添加到新视图会将其从旧视图中移除。
您需要 playerLayer
作为本地 属性 来查看。或者至少 AVPlayerLayer
用于您要播放的每个视频。然后,当每个视频可见时,您需要一个 pausing/restarting 机制。例如通过实施 viewWillAppear
。当您导航回视图/视图变为可见时,始终会调用此方法。
感谢@dominik-105 帮助解决这个问题。我能够使用提出的建议解决问题。
具体来说,我删除了 playerLayer 的全局定义,而是将其作为局部变量放在我的主视图调用中:
var playerLayer = AVPlayerLayer()
然后我使用 playerLayer: playerLayer 标签调用 ViewVideo,然后 ViewVideo 使用 playerLayer:AVPlayerLayer 调用 PlayVideo 作为初始化的一部分。
有趣的是,这导致我用来定义视频框大小的覆盖布局功能出现问题。我现在直接在 init 中定义框架并删除旧的覆盖功能代码。完整代码现在是:
import SwiftUI
import AVKit
import UIKit
import AVFoundation
class PlayVideo: UIView {
init(frame: CGRect, url: URL, playerLayer: AVPlayerLayer, width: CGFloat, height: CGFloat) {
super.init(frame: frame)
// Create the video player using the URL passed in.
let player = AVPlayer(url: url)
player.volume = 100 // Will play audio if you don't set to zero
player.play() // Set to play once created
// Add the player to our Player Layer
playerLayer.player = player
playerLayer.videoGravity = .resizeAspectFill // Resizes content to fill whole video layer.
playerLayer.backgroundColor = UIColor.black.cgColor
playerLayer.player?.actionAtItemEnd = .pause
layer.addSublayer(playerLayer)
playerLayer.frame = CGRect(x: 0, y: 0, width: width, height: height)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
struct ViewVideo: UIViewRepresentable {
var videoURL:URL
var playerLayer: AVPlayerLayer
var width: CGFloat
var height: CGFloat
func makeUIView(context: Context) -> UIView {
return PlayVideo(frame: .zero, url: videoURL, playerLayer: playerLayer, width: width, height: height)
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
我使用 GeometryReader 定义框的大小,然后将宽度和高度传递给结构,结构将其传递给 class。