gpt4 book ai didi

swiftui - 如何访问符合 UIViewRepresentable 的 SwiftUI 包装器中的属性?

转载 作者:行者123 更新时间:2023-12-04 04:05:39 24 4
gpt4 key购买 nike

我想控制 AVPlayer 的一个实例,该实例被实例化并分配给类 VideoPlayer 中的一个属性,该类符合 UIView。为了确保清楚我的意图,我在处理 SwiftUIUIViewRepresentable 包装器时将一个已知模式组合在一起,如下所示:

class VideoPlayer: UIView {
private let playerLayer = AVPlayerLayer()
private var previewTimer: Timer?
var previewLength: Double
var player: AVPlayer?

init(frame: CGRect, url: URL, previewLength:Double) {
self.previewLength = previewLength

super.init(frame: frame)
self.player = AVPlayer(url: url)
self.player?.volume = 0
self.player?.play()

NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: .main) { [weak self] _ in
self?.player?.seek(to: CMTime.zero)
self?.player?.play()
}

playerLayer.player = player
playerLayer.videoGravity = .resizeAspectFill
playerLayer.backgroundColor = UIColor.black.cgColor

previewTimer = Timer.scheduledTimer(withTimeInterval: previewLength, repeats: true, block: { (timer) in
self.player?.seek(to: CMTime(seconds: 0, preferredTimescale: CMTimeScale(1)))
})

layer.addSublayer(playerLayer)
}

required init?(coder: NSCoder) {
self.previewLength = 15
super.init(coder: coder)
}

override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}
}

包装器 MyWrapperUIView 暴露给 SwiftUI,并且 wrapper 可以具有公共(public)属性,例如 myState :

struct MyWrapper: UIViewRepresentable {
var videoURL: URL
var previewLength: Double
@Binding var mySate: Bool

func makeUIView(context: Context) -> UIView {
let videoPlayer = VideoPlayer(frame: .zero, url: videoURL, previewLength: previewLength)
return videoPlayer
}

func updateUIView(_ uiView: UIView, context: Context) {
if myState {
// do something
} else {
// do something else
}
}
}

如果需要控制 VideoPlayer 实例的属性,我们可能会想在 updateUIView 方法中直接从 UIView 对象访问属性>。因此,假设我们想要访问 player 属性:

func updateUIView(_ uiView: UIView, context: Context) {
if myState {
uiView.player.play()
}
}

这失败并出现错误 Value of type 'UIView' has no member 'player'

为了克服这个问题,在 MyWrapper 中创建了一个代理来引用 AVPlayer 实例,如下所示:

struct MyWrapper: UIViewRepresentable {
var videoURL: URL
var previewLength: Double
@State var player: AVPlayer?
@Binding var play: Bool

func makeUIView(context: Context) -> UIView {
let videoPlayer = VideoPlayer(frame: .zero, url: videoURL, previewLength: previewLength)
DispatchQueue.main.async {
self.player = videoPlayer.player
}
return videoPlayer
}

func updateUIView(_ uiView: UIView, context: Context) {
if play {
self.player?.play()
} else {
self.player?.pause()
self.player?.rate = 0
}
}
}

Obs:我们使用 DispatchQueue.main 绕过警告 在 View 更新期间修改状态,这将导致未定义的行为 将在 makeUIView 中抛出

这种方法有效,但我没有在 Apple 中找到任何文档来确认在处理 SwiftUI 和 UIViewRepresentable 包装器时这是正确的方法,因为 SwiftUI 是一个黑盒子。

因此,出于这个原因,我想知道如何访问符合 UIViewRepresentable 的 SwiftUI 包装器中的属性?

最佳答案

UIViewRepresentable 推断类型,在这种情况下,从声明的返回/参数类型推断类型,因此只需明确突出显示代表的类型

struct MyWrapper: UIViewRepresentable {
var videoURL: URL
var previewLength: Double
@Binding var mySate: Bool

func makeUIView(context: Context) -> VideoPlayer {
let videoPlayer = VideoPlayer(frame: .zero, url: videoURL, previewLength: previewLength)
return videoPlayer
}

func updateUIView(_ uiView: VideoPlayer, context: Context) {
if myState {
uiView.player.play() // now it knows that uiView is-a VideoPlayer
} else {
// do something else
}
}
}

关于swiftui - 如何访问符合 UIViewRepresentable 的 SwiftUI 包装器中的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62562718/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com