Search code examples
iosswiftautolayout

Cannot find superview while adding constrains programmatically?


Referring this question Making a custom UIView subview that fills its superview while trying to add constraints programmatically.

I am using the code below to add two constraints programmticly; however, I get an error states that "Unable to parse constraint format" because the related view doesn't have a superview.

private func setupDownView(view: UIView) {
    let downView = try? DownView(frame: view.bounds, markdownString: "")
    downView!.translatesAutoresizingMaskIntoConstraints = false
    let viewsDict = ["view": downView!]
    downView!.addConstraint(NSLayoutConstraint.constraints(
        withVisualFormat: "V:|-0-[view]-0-|",
        options: [],
        metrics: nil,
        views: viewsDict)[0])
    downView!.addConstraint(NSLayoutConstraint.constraints(
        withVisualFormat: "H:|-0-[view]-0-|",
        options: [],
        metrics: nil,
        views: viewsDict)[0])
    view.addSubview(downView!);
}

enter image description here

Does the view auto become the superview once it has been added to its subview?

I have tried to add the view before setting up the constrains by addSubview before addConstraint and I get the error "The view hierarchy is not prepared for the constraint".

enter image description here

setupDownView is called in the following two places,

@IBOutlet weak var cardTags: UIView! {didSet { setupDownView(view: cardTags)}}
@IBOutlet weak var cardContent: UIView! {
    didSet {
        setupDownView(view: cardContent)
        let tap = UILongPressGestureRecognizer(
            target: self,
            action: #selector(QuizViewController.tapDownHandler)
        )
        tap.minimumPressDuration = 0
        cardContent.addGestureRecognizer(tap)
    }
}

Solution

  • Constraints need to be added after view is in the hierarchy. So addSubview call must be before addConstraint calls.

    Also ensure that addConstraint is called on it's superview, not downView, and that all constraints returned from constraintsWithVisualFormat: are added, not only the first one.

    private func setupDownView(view: UIView) {
        let downView = try? DownView(frame: view.bounds, markdownString: "")
        downView!.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(downView!);
    
        let viewsDict = ["view": downView!]
        view.addConstraints(NSLayoutConstraint.constraints(
            withVisualFormat: "V:|-0-[view]-0-|",
            options: [],
            metrics: nil,
            views: viewsDict))
        view.addConstraints(NSLayoutConstraint.constraints(
            withVisualFormat: "H:|-0-[view]-0-|",
            options: [],
            metrics: nil,
            views: viewsDict))
    
        view.layoutIfNeeded()
    }