我有一个循环视频播放器,它应该根据给定的isPlaying
属性来播放或暂停。我最初创建了一个循环视频播放器(类似于this example的实现)--现在我希望能够暂停它。
UI在正确的播放/暂停状态下初始化视频,但当isPlaying
更改时,UI不会更新,除非卸载并重新渲染视图。
我使用print
来确认isPlaying
是正确的值,并且updateUIView
调用play
或pause
。
我想知道为什么UI不显示更新的视频播放/暂停。isPlaying
被传递到LoopingVideoPlayer
,如下所示
...
var body: some View {
LoopingVideoPlayer(
fileUrl: localUrl,
resizeMode: .resizeAspectFill,
isPlaying: isPlaying)
}
...
我的循环视频播放器的代码:
import SwiftUI
import AVKit
import AVFoundation
struct LoopingVideoPlayer: UIViewRepresentable {
var fileUrl: URL
var resizeMode: AVLayerVideoGravity
var isPlaying: Bool = true
private var loopingPlayerUIView: LoopingPlayerUIView
init(fileUrl: URL, resizeMode: AVLayerVideoGravity, isPlaying: Bool = true) {
self.fileUrl = fileUrl
self.resizeMode = resizeMode
self.isPlaying = isPlaying
self.loopingPlayerUIView = LoopingPlayerUIView(frame: .zero)
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LoopingVideoPlayer>) {
print("updateUIView called while isPlaying == \(isPlaying)")
if isPlaying {
loopingPlayerUIView.play()
} else {
loopingPlayerUIView.pause()
}
}
func makeUIView(context: Context) -> UIView {
print("makeUIView called")
loopingPlayerUIView.initPlayer(fileUrl: fileUrl, resizeMode: resizeMode)
return loopingPlayerUIView
}
}
class LoopingPlayerUIView: UIView {
private let playerLayer = AVPlayerLayer()
private let queuePlayer = AVQueuePlayer()
private var playerLooper: AVPlayerLooper?
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
playerLayer.player = queuePlayer
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}
func initPlayer(fileUrl: URL, resizeMode: AVLayerVideoGravity) {
print("initPlayer method invoked")
let avAsset = AVAsset(url: fileUrl)
let avPlayerItem = AVPlayerItem(asset: avAsset)
playerLayer.videoGravity = resizeMode
layer.addSublayer(playerLayer)
playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: avPlayerItem)
}
func play() {
print("play method invoked")
print("playerLayer reference matches queuePlayer: \(queuePlayer === playerLayer.player)")
queuePlayer.play()
}
func pause() {
print("pause method invoked")
print("playerLayer reference matches queuePlayer: \(queuePlayer === playerLayer.player)")
queuePlayer.pause()
}
}
1条答案
按热度按时间nkoocmlb1#
要更新
isPlaying
的值,你需要使用一个Binding变量。目前,当你将true或false传递给你的LoopingVideoPlayer
可表示对象时,你正在创建一个被初始化的值的副本。这意味着当你更新你的变量时,它不会更新LoopingVideoPlayer.
。然而,绑定创建了一个单一的真值源。新代码应如下所示:
然后,在您的父视图中,
isPlaying
变量应该是State值,如下所示:我建议阅读更多关于SwiftUI here中State和Binding之间关系的内容。