Set UIViewController view property to custom UIView class without storyboard / nib

前端 未结 4 1942
我在风中等你
我在风中等你 2021-02-07 02:16

I have a UIViewController called LoginViewController. I want to build the view of that LoginViewController fully programmatically<

相关标签:
4条回答
  • 2021-02-07 02:38

    It looks there are really two questions here. One, what is the best way to programmatically set up a ViewController. The other, how to set up a View programmatically.

    First, The best way to have a ViewController programmatically use a different UIView subclass is to initialize and assign it in the loadView method. Per Apple's docs:

    You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view hierarchy to the view property. The views you create should be unique instances and should not be shared with any other view controller object. Your custom implementation of this method should not call super.

    This would look something like this:

    class LoginViewController: UIViewController {    
        override func loadView() {
            // Do not call super!
            view = LoginView()
        }
    }
    

    This way you shouldn't have to deal with sizing it, as the View Controller itself should take care of it (as it does with it's own UIView).

    Remember, do not call super.loadView() or the controller will be confused. Also, the first time I tried this I got a black screen because I forgot to call window.makeKeyAndVisible() in my App Delegate. In this case the view was never even added to the window hierarchy. You can always use the view introspecter button in Xcode to see what's going on.

    Second, you will need to call self.addSubview(_:) in your UIView subclass in order to have them appear. Once you add them as subviews, you can add constraints with NSLayoutConstraint.

    private func setupLabels(){
        // Initialize labels and set their text
        usernameLabel = UILabel()
        usernameLabel.text = "Username"
        usernameLabel.translatesAutoresizingMaskIntoConstraints = false // Necessary because this view wasn't instantiated by IB
        addSubview(usernameLabel)
    
        passwordLabel = UILabel()
        passwordLabel.text = "Password"
        passwordLabel.translatesAutoresizingMaskIntoConstraints = false // Necessary because this view wasn't instantiated by IB
        addSubview(passwordLabel)
    
        NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[view]", options: [], metrics: nil, views: ["view":usernameLabel]))
        NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-20-[view]", options: [], metrics: nil, views: ["view":passwordLabel]))
    
        NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]", options: [], metrics: nil, views: ["view":usernameLabel]))
        NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-20-[view]", options: [], metrics: nil, views: ["view":passwordLabel]))
    }
    

    For more info on the visual format language used to create the constraints, see the VFL Guide

    0 讨论(0)
  • 2021-02-07 02:42

    Override the layoutSubviews method to update the frames of the subviews inside your custom view.

    And never call super.loadView(). This is documented for the loadView method.

    0 讨论(0)
  • 2021-02-07 02:44

    You should load the custom view when LoginViewController's layout constraints are already loaded, try this:

      override func viewDidLoad() {
          super.viewDidLoad()
          let newView = LoginView(frame: view.bounds)
          view.addSubview(newView)
        }
    
    0 讨论(0)
  • 2021-02-07 02:48

    In your Viewcontroller's loadView method do this:

    class LoginViewController: UIViewController {
        override func loadView() {
            super.view = LoginView()
        }
    }
    

    In your UIView's custom class do this:

    class LoginView: UIView {
        convenience init() {
            self.init(frame: UIScreen.main.bounds)
            setupLabels()
        }
    }
    

    Now your UIView has a frame , and you can setup all your views through code by providing them frames.

    0 讨论(0)
提交回复
热议问题