0

I am putting a UILabel inside a UIScrollView, I'd like to add these constraints to the label:

  1. Top margin is 20

  2. Left margin is 20

  3. Right margin is 20

  4. Label's height is 40

Here's the code I wrote for these constraints using visual format:

let label = UILabel.init(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Some Text"
scrollView.addSubview(label)

let horizontalConstraints = NSLayoutConstraint.constraints(
    withVisualFormat: "H:|-20-[label]-20-|",
    options: [],
    metrics: nil,
    views: ["label": label]
)

let verticalConstraints = NSLayoutConstraint.constraints(
    withVisualFormat: "V:|-20-[label(40)]",
    options: [],
    metrics: nil,
    views: ["label": label]
)

NSLayoutConstraint.activate(horizontalConstraints + verticalConstraints)

But this picture is what I'm getting (can't upload photo because I have low reputations). I added borders to the views, the blue one is the border of UIScrollView, the red one is the border of the UILabel

T.Le
  • 39
  • 7
  • Use `NSLayoutConstraint` is far better – black_pearl Sep 03 '18 at 03:06
  • Does the `scrollView` has its constraints already setup appropriately? – Ahmad F Sep 03 '18 at 05:43
  • Also, is it required to deal with [FVL](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage.html)? I would assume that there are easier options, you might want to check: https://stackoverflow.com/questions/26180822/how-to-add-constraints-programmatically-using-swift – Ahmad F Sep 03 '18 at 05:50
  • Thank you guys, I have posted an answer down there – T.Le Sep 03 '18 at 16:59

2 Answers2

0

Your code isn't correct. Here is how your code should looks. And if you use this way of adding constraints, you don't need to activate constraints with special method. These vertical and horizontal constraints have already activated.

//horizontal constraints
scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-20-[v0]-20-|", 
options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": label]))

//vertical constraints
scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-20-[v0(40)]", 
options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": label]))

Explanation of syntax:

"H", "V" - horizontal, vertical constraints

"|" - anchor, for example "H:|[v0]" - left anchor

"-20-" - offset, for example "V:|-20-[v0]" - top anchor with offset 20

"[v0(40)]" - this is the size of view, for example "V:[v0(40)]" - height is 40

"[v0]" - your first view in visual format. This format can set constraints for several views.

For example:

(format: "V:|-16-[v0]-8-[v1(44)]-16-[v2(1)]|", views: ["v0": firstView], ["v1": secondView], ["v2": thirdView])

Alex Kolovatov
  • 859
  • 7
  • 12
0

I figured out. Although I do not know why this happens, whether it's a bug with UIScrollView or things just have to be done this way.

Apparently, when you add subviews to a UIScrollView in Story Board, you'll always get a warning saying that the position of the subviews are ambiguous. So, what you would do is to add a UIView to the scroll view and add these constraints to it:

  1. Top = 0, Leading = 0, Trailing = 0 and Bottom = 0

  2. UIView is centered both horizontally and vertically in the scroll view

After that, you're good to add subviews to UIView without getting those warnings.

Same reason applies here, when you want to add subviews to a UIScrollView programmatically, and also set up some constraints, you should put a UIView inside the scroll view and put all subviews inside the UIView:

let subviewContainer = UIView.init(frame: .zero)
subviewContainer.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(subviewContainer)

var constraints: [NSLayoutConstraint] = []

// Step 1, set up horizontal constraints to make leading & trailing = 0
constraints += NSLayoutConstraint.constraints(
    withVisualFormat: "H:|-0-[subviewContainer]-0-|",
    options: [],
    metrics: nil,
    views: ["subviewContainer": subviewContainer]
)

// Step 2, set up vertical constraints to make top & bottom = 0
constraints += NSLayoutConstraint.constraints(
    withVisualFormat: "V:|-0-[subviewContainer]-0-|",
    options: [],
    metrics: nil,
    views: ["subviewContainer": subviewContainer]
)

// **Step 3, center "subviewContainer" horizontally & vertically in scroll view**
constraints.append(
    NSLayoutConstraint.init(
        item: subviewContainer,
        attribute: .centerX,
        relatedBy: .equal,
        toItem: scrollView,
        attribute: .centerX,
        multiplier: 1,
        constant: 0
    )
)

constraints.append(
    NSLayoutConstraint.init(
        item: subviewContainer,
        attribute: .centerY,
        relatedBy: .equal,
        toItem: scrollView,
        attribute: .centerY,
        multiplier: 1,
        constant: 0
    )
)

// Step 4, activate all constraints
NSLayoutConstraint.activate(constraints)

After these 4 steps, you are now good to add subviews to "subviewContainer".

T.Le
  • 39
  • 7