Bottom and Right constraints of view are negative?

2019-09-18 08:59发布

Here is a method in which I pin a subview to a UIView instance. Excuse the messy code, I have been experimenting trying to get this to work.

open static func withEmbeddedView(_ view: UIView, andFixedHeight height: CGFloat) -> PMGAlertControllerEmbedComponent {
    let base = PMGAlertControllerEmbedComponent(frame: CGRect.zero)
    base.addSubview(view)
    view.translatesAutoresizingMaskIntoConstraints = false
    base.translatesAutoresizingMaskIntoConstraints = false

    let left = NSLayoutConstraint(item: view, attribute: .left, relatedBy: .equal, toItem: base, attribute: .left, multiplier: 1, constant: 0)
    let right = NSLayoutConstraint(item: view, attribute: .right, relatedBy: .equal, toItem: base, attribute: .right, multiplier: 1, constant: 0)
    let top = NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: base, attribute: .top, multiplier: 1, constant: 0)
    let bottom = NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal, toItem: base, attribute: .bottom, multiplier: 1, constant: 0)
    base.addConstraints([left, right, top, bottom])
    view.addConstraint(NSLayoutConstraint(item: view, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: height))
    base.leftConstraint = left
    base.rightConstraint = right
    base.topConstraint = top
    base.bottomConstraint = bottom
    base.layoutIfNeeded()
    return base
}

Now this works fine in itself, but as soon as I try and modify these constraint's constants elsewhere, say making them 16 to add a bit of padding, the right and bottom constraints go the other way! So rather than the subview being smaller than the superview by 16pts its larger by 16pts? The top and left behave as expected.

Note that if I set the top and left to 16 but the bottom and right to -16 this produces the desired result but I shouldn't have to do this? Where am I going wrong?

Many Thanks.

2条回答
仙女界的扛把子
2楼-- · 2019-09-18 09:42

Sounds bonkers. Can't look at it right now but I tend to set the constraints up in storyboard, create outlets for them and change them like:

self.menuTopConstraint.constant = 64

would move the top constraint of a menu down to the bottom of the nav bar.

to slide my main view down by the height of the menu:

self.mainViewBottomConstraint.constant = self.indexHeight * -1

Appreciating it doesn't address the issue head on. Can look when I have more time.

查看更多
放我归山
3楼-- · 2019-09-18 09:44

The order of items in your constraint matters.

change

let bottom = NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal, toItem: base, attribute: .bottom, multiplier: 1, constant: 0)
let right = NSLayoutConstraint(item: view, attribute: .right, relatedBy: .equal, toItem: base, attribute: .right, multiplier: 1, constant: 0)

to

let bottom = NSLayoutConstraint(item: base, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
let right = NSLayoutConstraint(item: base, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1, constant: 0)

Try to think this way: treat the second item as the origin. if the value is positive, the first item is to the right / bottom direction of the second item. if the value is negative, that means the direction is to the left and top to the second item.

Since you want to put view inside the base, and you want positive value in constraint, you need to use base as first item, and view as second item (origin) in the constraint. So it means base is to the right/bottom to view when the constant of the constraint is positive .

查看更多
登录 后发表回答