简体   繁体   中英

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.

在此处输入图片说明

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?

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.

I think, that the easiest solution would be add an UIStackView to the wrapperView in the interface builder with no height, just add needed constraints (top, left, bottom, right). Then drag an IBOutlet of the UIStackView to your ViewController and when you will need to add a subview:

@IBOutlet weak var stackView: UIStackView!

func someFunc() {
  let myView = MyView.instanceFromNib()
  myView = CGRect(x: 0, y: 0, width: 300, height: 80)
  stackView.addArrangedSubview(myView)
}

UIStackView will change its size based on its subviews.

You may use the Debug View Hierarchy to debug your UI issues including the constraints which are failing to be satisfied. Most probably your .top constraint which is added at runtime is conflicting with .top constraint which you have set in your storyboard.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM