Search code examples
iosswiftnslayoutconstraint

Placing UiView as a subview programmatically


I have ViewController that looks like this. There is parent ScrollView that holds UIView (wrapperView) and this wrapper view has TextView and ImageView inside. This simple structure is created form interface builder with all constraints needed so it works fine.

enter image description here

In some cases I need to programmatically add one more UIView inside my wrapperView right under ImageView (green arrow points there).

So I created xib file for my new UIView and separate class for it

class MyView : UIView {
    class func instanceFromNib() -> UIView {
        return UINib(nibName: "MyView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
    }
}

And I code of my ViewController I added

let myView = MyView.instanceFromNib()
myView = CGRect(x: 0, y: 0, width: 300, height: 80)
wrapperView.addSubview(myView)

now i see myView on the screen in top of wrapperView but when i try to apply constraints like

NSLayoutConstraint(item: myView, attribute: .top, relatedBy: .equal, toItem: myImageView, attribute: .bottom, multiplier: 1.0, constant: 8).isActive = true

I got

Unable to simultaneously satisfy constraints

What am I doing wrong?


Solution

  • First you need to set this:

    myView.translatesAutoresizingMaskIntoConstraints = false
    

    And then you have to make sure that there are no your own constraints that are in conflict. In storyboard you have probably added a constraint that binds imageView.bottomAnchor to wrapperView.bottomAnchor. Now if you put between these two anchors another view, you need to deactivate that constraint.

    Otherwise if you try to squeeze myView there, it may result in constraint conflicts - imagine there is a constraint saying that

    1. imageView.bottomAnchor should be 10 points from wrapperView.bottomAnchor,

    but there are also two more constraints saying that

    1. imageView.bottomAnchor should be 10 points from myView.topAnchor and myView.bottomAnchor should be 10 points from wrapperView.bottomAnchor.

    Obviously both these scenarios cannot be satisfied.