About the problem of using UIViewController in swiftui that cannot update uibutton or uiview frame ui

123 Views Asked by At

This problem has troubled me for three days So I'm hoping to ask for some help Thank you so much

screenWidth & screenHeight

The value is correct and updated, but I don't understand why the UIViewController's view and the contained UIButton or PlayerLayer frame are not updated

enter image description here

enter image description here

struct PlayVideo: View {

    @State var screenCommnit : Bool = false 
    @State private var screenWidth: CGFloat = UIScreen.main.bounds.width UIScreen.main.scale
    @State private var screenHeight: CGFloat = 260   
              
 var body: some View {
 
        VStack{
            
            PlayerView(url: $url,screenCommnit:$screenCommnit,screenWidth:$screenWidth,screenHeight:$screenHeight).fixedSize()
         
            Spacer()
            
        } .onChange(of: screenCommnit) { newValue in 

          //Set landscape and portrait switch and set screenWidth and screenHeight
    }
}


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)
       
    }
}

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)
    }

}
1

There are 1 best solutions below

0
malhal On

makeUIViewController needs to init the controller, e.g.

func makeUIViewController(context: Context) -> MyViewController {
    let vc = MyViewController()
    vc.delegate = context.coordinator
    return vc
}

And you should not hang onto it in the struct because it will be lost when this struct is re-init. SwiftUI holds onto it for you and passes it in to updateUIViewController.

FYI since you have a UIViewController subclass you don't really need a coordinator object.

Also, since you only toggle screenCommit and don't read it you could replace it with a closure, e.g.

struct PlayerView : UIViewControllerRepresentable {
    let screenCommit: () -> Void

Use like:

PlayerView(...) {
    //on commit
}