I have a simple parent view controller and I'm adding a child view controller to it. Here's the parent:
class ParentViewController: UIViewController {
private var childViewController: ChildViewController!
override func viewDidLoad() {
super.viewDidLoad()
childViewController = ChildViewController()
addChild(childViewController)
view.addSubview(childViewController.view)
childViewController.didMove(toParent: self)
NSLayoutConstraint.activate([
childViewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100),
childViewController.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 50),
childViewController.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -50),
childViewController.view.heightAnchor.constraint(equalToConstant: 100)
])
}
}
The child view controller is declared like this:
class ChildViewController: UIViewController {
private let label1: UILabel = {
let label = UILabel()
label.text = "First label"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let label2: UILabel = {
let label = UILabel()
label.text = "Second label"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemYellow
view.translatesAutoresizingMaskIntoConstraints = false
setupSubViews()
}
private func setupSubViews() {
view.addSubview(label1)
view.addSubview(label2)
print("view.frame.size: \(view.frame.size)")
NSLayoutConstraint.activate([
label1.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8),
label1.centerYAnchor.constraint(equalTo: view.topAnchor, constant: self.view.frame.size.height * (1/3)),
label2.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8),
label2.centerYAnchor.constraint(equalTo: view.topAnchor, constant: self.view.frame.size.height * (2/3)),
])
}
}
Running the code produces the following:
The position of the two labels are obviously not what I intended. What I'm trying to do in the child view controller is define centerYAnchor constraints for the two labels using the height of the child view controller's view after it has been positioned in the parent view controller. If I print out the value of view.frame.size
inside of setupSubViews()
in my child view controller, the size of the view is the entire screen (428.0 x 926.0, in my case). Presumably, this is because the child view controller's view hasn't been fully loaded/positioned in the parent view controllers view yet?
So I moved the call to setupSubViews()
into viewDidLayoutSubviews()
of the child view controller and then the value of view.frame.size
is correct (328.0 x 100.0) and the labels are positioned correctly within the child view controller's view. But I do see viewDidLayoutSubviews()
being called multiple times, though, so I'm wondering if that's really the "correct" lifecycle method for declaring constraints like this? I've seen some people suggest using a boolean to ensure that the constraint code only runs once but I'm not sure that's the right way to handle this situation either.