Skip to content

Instantly share code, notes, and snippets.

@christianselig
Created August 10, 2022 19:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save christianselig/e1f12ee50b1f12cb155571d094e11f7e to your computer and use it in GitHub Desktop.
Save christianselig/e1f12ee50b1f12cb155571d094e11f7e to your computer and use it in GitHub Desktop.
import UIKit
class ViewController: UIViewController {
var redBox: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Trying to migrate some old frame based code to Auto Layout
redBox = UIView()
redBox.backgroundColor = .systemRed
redBox.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(redBox)
NSLayoutConstraint.activate([
redBox.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50.0),
redBox.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -50.0),
redBox.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
redBox.heightAnchor.constraint(equalToConstant: 50.0)
])
let childViewController = ViewControllerB(holderViewController: self)
childViewController.view.frame = view.bounds
addChild(childViewController)
view.addSubview(childViewController.view)
childViewController.didMove(toParent: self)
view.backgroundColor = .systemBackground
}
}
class ViewControllerB: UIViewController {
private(set) weak var holderViewController: ViewController?
init(holderViewController: ViewController) {
self.holderViewController = holderViewController
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) { fatalError("\(#file) does not implement coder.") }
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
let greenBox = UIView()
greenBox.backgroundColor = .systemGreen
greenBox.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(greenBox)
// Dispatching ahead one cycle allows the parent to be added, but feels gross
// If I *don't* dispatch ahead, the parent isn't part of the hiearchy yet, therefore
// has no common ancestor, and the constraint crashes.
DispatchQueue.main.async {
NSLayoutConstraint.activate([
greenBox.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 50.0),
greenBox.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -50.0),
greenBox.bottomAnchor.constraint(equalTo: self.holderViewController!.redBox.topAnchor),
greenBox.heightAnchor.constraint(equalToConstant: 50.0)
])
}
}
}
@rogelin
Copy link

rogelin commented Aug 10, 2022

my ugly aproach

import UIKit 

class ViewController: UIViewController {
    var redBox: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Trying to migrate some old frame based code to Auto Layout
        redBox = UIView()
        redBox.backgroundColor = .systemRed
        redBox.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(redBox)
        
        let childViewController = ViewControllerB(holderViewController: self)
        childViewController.view.frame = view.bounds
        addChild(childViewController)
        view.addSubview(childViewController.view)
        childViewController.didMove(toParent: self)
        
        view.backgroundColor = .systemBackground
        
        if let children = children.last?.view.subviews.first {
            NSLayoutConstraint.activate([
                redBox.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50.0),
                redBox.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -50.0),
                redBox.bottomAnchor.constraint(equalTo: children.topAnchor),
                redBox.heightAnchor.constraint(equalToConstant: 50.0)
            ])
        }
    }
}

class ViewControllerB: UIViewController {
    private(set) weak var holderViewController: ViewController?
    
    init(holderViewController: ViewController) {
        self.holderViewController = holderViewController
        
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder aDecoder: NSCoder) { fatalError("\(#file) does not implement coder.") }
    
    let greenBox = UIView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .clear
        
        greenBox.backgroundColor = .systemGreen
        greenBox.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(greenBox)
        
    }
    
    override func didMove(toParent parent: UIViewController?) {
        super.didMove(toParent: parent)
        
        guard let parent = parent else { return }
        NSLayoutConstraint.activate([
            self.greenBox.leadingAnchor.constraint(equalTo: parent.view.leadingAnchor, constant: 50.0),
            self.greenBox.trailingAnchor.constraint(equalTo: parent.view.trailingAnchor, constant: -50.0),
            self.greenBox.bottomAnchor.constraint(equalTo: parent.view.bottomAnchor),
            self.greenBox.heightAnchor.constraint(equalToConstant: 50.0)
        ])
        parent.view.setNeedsLayout()
        parent.view.layoutIfNeeded()
    }
}

@bjtitus
Copy link

bjtitus commented Aug 10, 2022

@rogelin's approach makes sense, IMO. You could set normal constraints in viewDidLoad and then the constraint which relies on the parent in didMove(toParent:):

private var greenBoxBottomConstraint: NSLayoutConstraint?

override func didMove(toParent parent: UIViewController?) {
    super.didMove(toParent: parent)
    resetGreenBoxBottomConstraint(parent: parent)
}

func resetGreenBoxBottomConstraint(parent: UIViewController?) {
    greenBoxBottomConstraint?.isActive = false

    if let redBox = (parent as? ViewController)?.redBox {
        greenBoxBottomConstraint = greenBox.bottomAnchor.constraint(equalTo: redBox.topAnchor)
    } else {
        greenBoxBottomConstraint = greenBox.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
    }

    greenBoxBottomConstraint?.isActive = true
}

I think it'd also be cleaner to expose a custom layout guide instead of redBox. There's an example in my fork.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment