将 uiviewcontroller 视图替换为自定义视图是否正确?

Is it correct to replace uiviewcontroller view to custom view?

提问人:Mohd Haider 提问时间:9/29/2022 更新时间:9/18/2023 访问量:306

问:

我正在尝试在运行时更新我的 uivewicontroller 视图层次结构。 它工作正常,但我不确定是否是正确的做法。

正如我所看到的,UIViewController 的根视图属性具有 setter。

https://developer.apple.com/documentation/uikit/uiviewcontroller/1621460-view

下面是代码示例:

@IBAction func showUserDetailsScreen() {
    let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
    let controller = storyboard.instantiateViewController(withIdentifier: "UserDetailsVC")
    
    /* The basic idea is to replace "UIViewController root view" to
     "my custom message view" and then adding initial "UIViewController root view" as
     subview to "my custom message view".
     So view hierarchy will be like as follow:
     
     Old: UserDetailsVC >> view
     New: UserDetailsVC >> SecureView >> view
     
     Is it a safe and correct practice to do this?
     */
    
    if let secureView = createSecureView() {
        
        let bgView = UIView()
        bgView.backgroundColor = .blue
        secureView.frame = self.view.bounds
        secureView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        
        bgView.addSubview(secureView)
        
        let controllerView = controller.view
        
        bgView.frame = controller.view.bounds
        bgView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        
        // Exchanging UserDetailsVC's view to Custom view.
        controller.view = bgView
        
        if let view = controllerView {
            
            view.frame = controller.view.bounds
            view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            
            // Adding initial UserDetailsVC's view as subview to secure view.
            secureView.addSubview(view)
        }
    }
    
    navigationController?.pushViewController(controller, animated: true)
}

private func createSecureView() -> UIView? {
    
    if let view = Bundle.main.loadNibNamed("SecureView", owner: nil, options: nil)?.first as? SecureView {
        return view
    }
    
    return nil
}

与任何现有项目一样,UIViewContoller 可以具有非常复杂的视图层次结构。因此,这是一个快速简便的修复程序,可以控制所有屏幕。

欢迎任何建议或反馈。

iOS Swift iPhone UIView UIVieviceController

评论

2赞 Fabio Felici 9/30/2022
据我所知,只有在覆盖时才应该手动设置.对我来说,你的问题似乎可以通过使用装饰器模式来解决。我会创建一个用安全视图装饰任何传递的 VC。您需要知道如何创建容器 VC ( API) 才能正常工作。当然,可能还有其他方法,但我不会继续你在这里做的事情。UIViewController.viewloadView()SecureViewDecoratorController<VC: UIViewController>addChild
0赞 Fattie 9/18/2023
正如大家所说,您只需在此处使用容器视图,这个概念完全内置于 iOS 中,并为此目的而存在。完全忘记你在做什么。

答:

1赞 Miles 10/1/2022 #1

不应在 之外进行更改。不确定它是否会正常运行,但无论哪种方式,这都是一个坏主意,因为它可能会导致混淆是什么。UIViewController.viewloadView()view

相反,您应该让所有这些层次结构都发生在 .例如,在 :SecureViewUserDetailsVCviewDidLoad()

self.view.addSubview(self.bgView)
self.bgView.addSubview(self.secureView)
self.secureView.addSubview(self.contentView) // content view could be what you were putting as `UserDetailsVC.view` 

或者,如果你需要在具有不同通用视图控制器的应用程序中更好地重用它,那么一个简单的方法(许多方法)就是拥有一个其他视图控制器(如继承)的类。SecureViewControllerUserDetailsVC

class SecureViewController: UIViewController {

    let secureView = SecureView()

    override func loadView() {
        self.view = self.secureView
    }
}

class UserDetailsVC: SecureViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    
        self.view.addSubview(AnyViewYouWant()) // since self.view refers to secureView, you're adding to the secureView
    
        // This is the same as:
        self.secureView.addSubview(AnyViewYouWant())
    }
}
1赞 Fattie 9/18/2023 #2

您只需使用容器视图即可实现此目的

它们已经内置到 iOS / UIKit 中 15+?年。

您始终使用容器视图来执行 iOS 中的所有操作。

在情节提要中,只需单击即可添加容器视图...

enter image description here

由于它可能是每个iOS布局中最基本的构建块,因此您可以找到无数的教程等。

这是一个很长的细节,如果你愿意,它还清楚地解释了如何在代码中做到这一点(这很容易)。