swift 如何避免在UIViewController中调用viewSafeAreaInsetsDidChange()

ql3eal8s  于 2023-08-02  发布在  Swift
关注(0)|答案(1)|浏览(197)

我有一个子视图控制器,它不希望在旋转时调用系统安全区域或viewSafeAreaInsetsDidChange()。到目前为止,这还不起作用:
在Superview中:

let childVC = UIViewController()
self.addChild(childVC)
childVC.view.frame = CGRect(x:0, y: self.view.bounds.height - 300, width: self.view.bounds.width, height: 300)
self.view.addSubview(childVC.view)
childVC.didMove(toParent: self)

字符串
在子视图控制器中:

class childVC: UIViewController {
    let picker = UIPickerView()
    
    override final func loadView() {
        super.loadView()
    
        self.viewRespectsSystemMinimumLayoutMargins = false
        self.view.insetsLayoutMarginsFromSafeArea   = false
        self.view.preservesSuperviewLayoutMargins.  = false
    }

    override final func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        //Some mention this to be inside viewDidAppear
        self.viewRespectsSystemMinimumLayoutMargins = false
        self.view.insetsLayoutMarginsFromSafeArea = false
        self.view.preservesSuperviewLayoutMargins = false

        //Add picker view here
        self.picker.delegate = self
        self.picker.dataSource = self
        self.picker.frame = self.view.bounds
        self.view.addSubview(self.picker)
    }

    override func viewSafeAreaInsetsDidChange() {
        super.viewSafeAreaInsetsDidChange()
        //This gets called everytime the device rotates, causing the picker view to redraw and reload all components. Trying to avoid this method being called.

        print ("viewSafeAreaInsetsDidChange")
        print (self.view.safeAreaInsets)
    }
}

问题

每次设备旋转时,viewSafeAreaInsetsDidChange()都会被调用,导致拾取器视图重新绘制和重新加载。

目标

尝试避免每次设备旋转时调用viewSafeAreaInsetsDidChange()

fykwrbwg

fykwrbwg1#

第一个月
调用以通知视图控制器其根视图的安全区域插入已更改。
这是一个“通知”电话。你忽略它,或者回应它…但是你不能阻止安全区域插图的改变。
这两个例子:https://pastebin.com/vLkNj6vyhttps://pastebin.com/cZPTZ17C显示viewSafeAreaInsetsDidChange()在设备旋转时被调用,但选择器视图重新加载。
如果选取器视图的框架在受影响的安全区域更改之外,则将重新加载选取器视图。
下面是一个简单的例子:

class MovingPickerVC: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
    
    let picker = UIPickerView()
    
    var vConstraints: [NSLayoutConstraint] = []
    var hConstraints: [NSLayoutConstraint] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        
        picker.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(picker)

        // keep picker INSIDE the safe-area
        //  this WILL NOT cause reload on device rotation
        let g = view.safeAreaLayoutGuide
        
        // extend picker frame OUTSIDE the safe-area
        //  this WILL cause reload on device rotation
        //let g = self.view!
        
        NSLayoutConstraint.activate([
            picker.widthAnchor.constraint(equalToConstant: 300.0),
            picker.heightAnchor.constraint(equalToConstant: 160.0),
        ])

        vConstraints = [
            picker.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            picker.bottomAnchor.constraint(equalTo: g.bottomAnchor),
        ]
        hConstraints = [
            picker.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            picker.trailingAnchor.constraint(equalTo: g.trailingAnchor),
        ]

        // so we can see its frame
        picker.backgroundColor = .yellow
        
        self.picker.delegate = self
        self.picker.dataSource = self
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if self.traitCollection.verticalSizeClass == .regular {
            NSLayoutConstraint.activate(vConstraints)
        } else {
            NSLayoutConstraint.activate(hConstraints)
        }
    }
    
    override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
        super.willTransition(to: newCollection, with: coordinator)
        
        coordinator.animate(alongsideTransition: { [unowned self] _ in
            if newCollection.verticalSizeClass == .regular {
                NSLayoutConstraint.deactivate(self.hConstraints)
                NSLayoutConstraint.activate(self.vConstraints)
            } else {
                NSLayoutConstraint.deactivate(self.vConstraints)
                NSLayoutConstraint.activate(self.hConstraints)
            }
        }) { [unowned self] _ in
            // if we want to do something on completion
        }
        
    }
    override func viewSafeAreaInsetsDidChange() {
        super.viewSafeAreaInsetsDidChange()
        //This gets called everytime the device rotates, causing the picker view to redraw and reload all components. Trying to avoid this method being called.
        
        print ("viewSafeAreaInsetsDidChange")
        print (self.view.safeAreaInsets)
    }
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        print("num components: 1")
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        print("num rows: 30")
        return 30
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        print("Title for Row:", row)
        return "Row: \(row)"
    }
    
}

字符串
看起来像这样:
x1c 0d1x的数据
旋转该装置:



当它运行时,我们看到viewSafeAreaInsetsDidChange()被记录,但是选择器视图将不会重新加载。
但是在viewDidLoad()中,如果我们将约束改为view而不是safe area

// keep picker INSIDE the safe-area
    //  this WILL NOT cause reload on device rotation
    //let g = view.safeAreaLayoutGuide
    
    // extend picker frame OUTSIDE the safe-area
    //  this WILL cause reload on device rotation
    let g = self.view!




我们已经将选择器视图框放置在安全区域之外,并且它将在旋转时重新加载。
如果你不想让选择器重新加载(由于某种原因),你需要通过你的dataSource / delegate函数来管理它。

相关问题