SwiftUI嵌入UIViewController无法更新UIButton/PlayerLayer帧的问题求助
PlayerView.swift
struct PlayerView : UIViewControllerRepresentable { @Binding var screenCommnit : Bool @Binding var screenWidth : CGFloat @Binding var screenHeight : CGFloat let controller = MyViewController() func makeUIViewController(context: Context) -> MyViewController { print("makeUIViewController") return controller } func updateUIViewController(_ uiViewController: MyViewController, context: Context) { print("updateUIViewController") controller.screenCommnit = screenCommnit controller.screenWidth = screenWidth controller.screenHeight = screenHeight controller.delegate = context.coordinator let size = controller.view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) controller.preferredContentSize = size } func makeCoordinator() -> PlayerView.Coordinator { Coordinator(url:$url, screenCommnit:$screenCommnit,screenWidth:$screenWidth,screenHeight:$screenHeight) } }
MyViewController.swift
class MyViewController: UIViewController { var url: String = "" var screenCommnit : Bool = false var screenWidth: CGFloat = UIScreen.main.bounds.width var screenHeight: CGFloat = 260 var fullScreenBtn = UIButton() var uiView = UIView() var delegate : PlayerViewDelegate? override func viewDidLoad() { super.viewDidLoad() print("viewDidLoad...") self.view.backgroundColor = .white self.view.frame = CGRect(x: 0, y: 0, width:self.screenWidth, height: self.screenHeight) self.PlayerLayer() self.ScreenButton() } func ScreenButton(){ print("ScreenButton...") fullScreenBtn.frame = CGRect.init(x: -20, y: 30, width: 200, height: 30) fullScreenBtn.setTitle("全屏", for: .normal) fullScreenBtn.setImage(UIImage(systemName: "arrow.up.and.down.circle"), for:.normal) fullScreenBtn.tag = 1 fullScreenBtn.addTarget(self,action:#selector(btnClick), for: .touchUpInside) self.view.insertSubview(fullScreenBtn, at:1) } func PlayerLayer(){ print("PlayerLayer...") let playerLayer = AVPlayerLayer(player: AVPlayer(url: URL(string: "https://media.w3.org/2010/05/sintel/trailer.mp4")!)) print("PlayerLayer() : \(self.view.frame.width) \(self.view.frame.height)") playerLayer.frame = CGRect.init(x: 0, y: 9, width: screenWidth, height: screenHeight) playerLayer.frame.size.height = playerLayer.frame.size.height * 0.92 playerLayer.videoGravity = .resizeAspect playerLayer.backgroundColor = UIColor.black.cgColor playerLayer.player?.play() self.view.layer.insertSublayer(playerLayer, at: 0) } @objc func btnClick(btn: UIButton) { screenCommnit = !screenCommnit delegate?.OneGroupDidFinished(self) } override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } required init?(coder: NSCoder) { super.init(coder: coder) } }
解决方案
核心问题分析
viewDidLoad仅执行一次,后续screenWidth/screenHeight更新时,没有重新触发视图、按钮和PlayerLayer的帧更新逻辑AVPlayerLayer创建后未保存引用,无法在尺寸变化时修改它的帧PlayerView的updateUIViewController仅更新了controller的属性,没有触发实际的视图刷新
具体修复步骤
1. 修改MyViewController,添加帧更新方法并保存PlayerLayer引用
class MyViewController: UIViewController { var url: String = "" var screenCommnit : Bool = false var screenWidth: CGFloat = UIScreen.main.bounds.width var screenHeight: CGFloat = 260 var fullScreenBtn = UIButton() var uiView = UIView() var delegate : PlayerViewDelegate? // 保存PlayerLayer引用,用于后续更新 private var playerLayer: AVPlayerLayer? override func viewDidLoad() { super.viewDidLoad() print("viewDidLoad...") self.view.backgroundColor = .white // 初始化时调用更新方法 updateAllFrames() self.PlayerLayer() self.ScreenButton() } // 新增:统一更新所有元素的帧 func updateAllFrames() { // 更新主视图尺寸 self.view.frame = CGRect(x: 0, y: 0, width: self.screenWidth, height: self.screenHeight) // 更新全屏按钮的位置(可根据需求调整相对布局) fullScreenBtn.frame = CGRect(x: -20, y: 30, width: 200, height: 30) // 更新PlayerLayer尺寸 if let layer = playerLayer { layer.frame = CGRect(x: 0, y: 9, width: screenWidth, height: screenHeight) layer.frame.size.height = layer.frame.size.height * 0.92 } } func ScreenButton(){ print("ScreenButton...") fullScreenBtn.setTitle("全屏", for: .normal) fullScreenBtn.setImage(UIImage(systemName: "arrow.up.and.down.circle"), for:.normal) fullScreenBtn.tag = 1 fullScreenBtn.addTarget(self,action:#selector(btnClick), for: .touchUpInside) self.view.insertSubview(fullScreenBtn, at:1) // 移除这里的frame设置,统一交给updateAllFrames处理 } func PlayerLayer(){ print("PlayerLayer...") let playerLayer = AVPlayerLayer(player: AVPlayer(url: URL(string: "https://media.w3.org/2010/05/sintel/trailer.mp4")!)) playerLayer.videoGravity = .resizeAspect playerLayer.backgroundColor = UIColor.black.cgColor playerLayer.player?.play() self.view.layer.insertSublayer(playerLayer, at: 0) // 保存PlayerLayer引用 self.playerLayer = playerLayer // 初始frame交给updateAllFrames设置 } @objc func btnClick(btn: UIButton) { screenCommnit = !screenCommnit delegate?.OneGroupDidFinished(self) } override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } required init?(coder: NSCoder) { super.init(coder: coder) } }
2. 修改PlayerView,在updateUIViewController中触发帧更新
struct PlayerView : UIViewControllerRepresentable { @Binding var screenCommnit : Bool @Binding var screenWidth : CGFloat @Binding var screenHeight : CGFloat let controller = MyViewController() func makeUIViewController(context: Context) -> MyViewController { print("makeUIViewController") return controller } func updateUIViewController(_ uiViewController: MyViewController, context: Context) { print("updateUIViewController") controller.screenCommnit = screenCommnit controller.screenWidth = screenWidth controller.screenHeight = screenHeight controller.delegate = context.coordinator // 触发controller更新所有元素的帧 controller.updateAllFrames() // 直接设置preferredContentSize,适配SwiftUI布局 controller.preferredContentSize = CGSize(width: screenWidth, height: screenHeight) } func makeCoordinator() -> PlayerView.Coordinator { Coordinator(url:$url, screenCommnit:$screenCommnit,screenWidth:$screenWidth,screenHeight:$screenHeight) } }
3. 修正PlayVideo中的语法错误
初始化screenWidth时补充乘号:
@State private var screenWidth: CGFloat = UIScreen.main.bounds.width * UIScreen.main.scale
内容的提问来源于stack exchange,提问作者jy02411368
相关产品推荐
相关产品推荐

