SwiftUI 中 AVPlayerLayer 的帧大小更新
AVPlayerLayer's frame size update in SwiftUI
我有一个异步加载视频并通过另一个 UIViewRepresentable
视图呈现的视图。 GeometryReader
提供视频容器的框架,然后用于初始化 AVPlayerLayer
。当设备方向改变时出现问题(因此,容器的框架也改变了),并且 AVPlayerLayer
不会重新布局自身以匹配容器。我尝试在 updateUIView
内更新图层的框架,甚至调用 setNeedsLayout
和 setNeedsDisplay
到图层和 uiView
,但没有任何改变。
如何调整图层以匹配容器的大小?
struct VideoView: View {
@StateObject var videoLoader: VideoLoader
@ViewBuilder
var body: some View {
if let player = videoLoader.player {
GeometryReader { geometry in
let frame = geometry.frame(in: .local)
VideoPlayerView(frame: frame, player: player)
.frame(width: frame.width, height: frame.height)
.onAppear { player.play() }
.onDisappear { player.pause() }
}
}
}
}
struct VideoPlayerView: UIViewRepresentable {
private let frame: CGRect
private let playerLayer: AVPlayerLayer
init(frame: CGRect, player: AVPlayer) {
self.frame = frame
self.playerLayer = AVPlayerLayer(player: player)
self.playerLayer.frame = frame
}
func makeUIView(context: Context) -> UIView {
let container = UIView()
container.layer.addSublayer(playerLayer)
return container
}
func updateUIView(_ uiView: UIView, context: Context) {
playerLayer.frame.size = uiView.frame.size
}
}
解决方案是创建自定义 UIView
并在 layoutSubviews()
中更新图层的帧大小。
struct VideoPlayerView: UIViewRepresentable {
class PlayerContainer: UIView {
init(playerLayer: AVPlayerLayer) {
super.init(frame: .zero)
layer.addSublayer(playerLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
layer.sublayers?.first?.frame = frame
}
}
private let playerLayer: AVPlayerLayer
init(player: AVPlayer) {
playerLayer = AVPlayerLayer(player: player)
}
func makeUIView(context: Context) -> UIView {
return PlayerContainer(playerLayer: playerLayer)
}
func updateUIView(_ uiView: UIView, context: Context) { }
}
我有一个异步加载视频并通过另一个 UIViewRepresentable
视图呈现的视图。 GeometryReader
提供视频容器的框架,然后用于初始化 AVPlayerLayer
。当设备方向改变时出现问题(因此,容器的框架也改变了),并且 AVPlayerLayer
不会重新布局自身以匹配容器。我尝试在 updateUIView
内更新图层的框架,甚至调用 setNeedsLayout
和 setNeedsDisplay
到图层和 uiView
,但没有任何改变。
如何调整图层以匹配容器的大小?
struct VideoView: View {
@StateObject var videoLoader: VideoLoader
@ViewBuilder
var body: some View {
if let player = videoLoader.player {
GeometryReader { geometry in
let frame = geometry.frame(in: .local)
VideoPlayerView(frame: frame, player: player)
.frame(width: frame.width, height: frame.height)
.onAppear { player.play() }
.onDisappear { player.pause() }
}
}
}
}
struct VideoPlayerView: UIViewRepresentable {
private let frame: CGRect
private let playerLayer: AVPlayerLayer
init(frame: CGRect, player: AVPlayer) {
self.frame = frame
self.playerLayer = AVPlayerLayer(player: player)
self.playerLayer.frame = frame
}
func makeUIView(context: Context) -> UIView {
let container = UIView()
container.layer.addSublayer(playerLayer)
return container
}
func updateUIView(_ uiView: UIView, context: Context) {
playerLayer.frame.size = uiView.frame.size
}
}
解决方案是创建自定义 UIView
并在 layoutSubviews()
中更新图层的帧大小。
struct VideoPlayerView: UIViewRepresentable {
class PlayerContainer: UIView {
init(playerLayer: AVPlayerLayer) {
super.init(frame: .zero)
layer.addSublayer(playerLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
layer.sublayers?.first?.frame = frame
}
}
private let playerLayer: AVPlayerLayer
init(player: AVPlayer) {
playerLayer = AVPlayerLayer(player: player)
}
func makeUIView(context: Context) -> UIView {
return PlayerContainer(playerLayer: playerLayer)
}
func updateUIView(_ uiView: UIView, context: Context) { }
}