Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Horizontal constraint not working correctly in a UIScrollView. (programatic constraints)

Quick explanation.

I have a UIScrollView, that's a sub-view of "self.view". My UIScrollview, has a subview called contentView

All my other objects are subviews of contentView or it's sub-views

I got everything looking correctly, with the exception of 2 views.

Once I add these views in my constraints. The entire contentView shifts to the left, and breaks everything.

Here's an image of the screen with the troublesome view called (howManyIconView), it's the blue UIView, with a white slack icon in the middle. (bottom left)

To make it clear to everyone that it's the contentView that's getting messed up, I gave the contentView a red background.

enter image description here

Here is the same view, without adding the howManyIconView to my constraint.

enter image description here

To the actual code related to the problem, starting from the top.

contentView.setTranslatesAutoresizingMaskIntoConstraints(false)
scrollView.addSubview(contentView)

howManyContentView.setTranslatesAutoresizingMaskIntoConstraints(false)
contentView.addSubview(howManyContentView)

howManyIconView.setTranslatesAutoresizingMaskIntoConstraints(false)
howManyIconView.backgroundColor = UIColor.formulaBlueColor()
howManyContentView.addSubview(howManyIconView)

howManyIcon.setTranslatesAutoresizingMaskIntoConstraints(false)
howManyIcon.textColor = UIColor.formulaWhiteColor()
howManyIcon.font = UIFont(name: "fontAwesome", size: 20)
howManyIcon.text = ""
howManyIconView.addSubview(howManyIcon)

And here's the constraints:

    var viewsDictionary = ["contentView":contentView,"howManyContentView":howManyContentView,
            "howManyLabel":howManyLabel,
            "howManyInputField":howManyInputField,
            "howManyIconView":howManyIconView,
            "howManyIcon":howManyIcon]

    let metricsDictionary = ["topBarHeight":6,"numbersViewRowHeight":49,"numbersViewSeperatorHeight":1,"inputFieldHeight":75,"contentWidth":self.view.bounds.width,"grapViewHeight":175,"inputFieldWidth":100,"iconViewWidth":50]

            scrollView.addConstraints(
            NSLayoutConstraint.constraintsWithVisualFormat(
                "H:[contentView(contentWidth)]", options: NSLayoutFormatOptions(0), metrics: metricsDictionary, views: viewsDictionary))

        howManyContentView.addConstraints(
            NSLayoutConstraint.constraintsWithVisualFormat(
                "V:[howManyIconView(inputFieldHeight)]", options: NSLayoutFormatOptions(0), metrics: metricsDictionary, views: viewsDictionary))
        howManyContentView.addConstraints(
            NSLayoutConstraint.constraintsWithVisualFormat(
                "V:[howManyInputField(inputFieldHeight)]", options: NSLayoutFormatOptions(0), metrics: metricsDictionary, views: viewsDictionary))

contentView.addConstraints(
            NSLayoutConstraint.constraintsWithVisualFormat(
                "H:|[howManyContentView]|", options: nil, metrics: nil, views: viewsDictionary))

        howManyContentView.addConstraint(NSLayoutConstraint(item:howManyLabel, attribute:NSLayoutAttribute.CenterY, relatedBy:NSLayoutRelation.Equal, toItem:howManyContentView, attribute:NSLayoutAttribute.CenterY, multiplier:1.0, constant:0))
        howManyContentView.addConstraint(NSLayoutConstraint(item:howManyInputField, attribute:NSLayoutAttribute.CenterY, relatedBy:NSLayoutRelation.Equal, toItem:howManyContentView, attribute:NSLayoutAttribute.CenterY, multiplier:1.0, constant:0))
        howManyContentView.addConstraint(NSLayoutConstraint(item:howManyIconView, attribute:NSLayoutAttribute.CenterY, relatedBy:NSLayoutRelation.Equal, toItem:howManyContentView, attribute:NSLayoutAttribute.CenterY, multiplier:1.0, constant:0))
        howManyIconView.addConstraint(NSLayoutConstraint(item:howManyIcon, attribute:NSLayoutAttribute.CenterY, relatedBy:NSLayoutRelation.Equal, toItem:howManyIconView, attribute:NSLayoutAttribute.CenterY, multiplier:1.0, constant:0))
        howManyIconView.addConstraint(NSLayoutConstraint(item:howManyIcon, attribute:NSLayoutAttribute.CenterX, relatedBy:NSLayoutRelation.Equal, toItem:howManyIconView, attribute:NSLayoutAttribute.CenterX, multiplier:1.0, constant:0))


        howManyContentView.addConstraints(
    NSLayoutConstraint.constraintsWithVisualFormat(
        "H:|-32-[howManyLabel]", options: nil, metrics: metricsDictionary, views: viewsDictionary))

The below constraint, is the one that messes everything up. Once I remove [howManyIconView(iconViewWidth)] from that 1 line of code, everything is fine.

howManyContentView.addConstraints(
    NSLayoutConstraint.constraintsWithVisualFormat(
        "H:[howManyIconView(iconViewWidth)][howManyInputField(inputFieldWidth)]-32-|", options: nil, metrics: metricsDictionary, views: viewsDictionary))

I have triple checked that howManyContentView, howManyIconView, and howManyIcon are not mentioned in any code not shown in this post.

Here's what I have tried to solve my problem

First off I attempted to make another view called HowManyInputView, where I put the iconView and UITextField in. Then putting that as the only constraint. (same outcome)

Afterwards I tried to remove everything that had to do with the UILabel inside the iconView. To see if it had something to do with the label. (Same outcome)

Then I tried making a new view. and gave it similar (but not the same) positional constraints (same problem), this view also didn't have any subviews, further showing that it's the view and not the UILabel causing my issues.

So I tried splitting my horizontal constraint in 2. Before as you can see in the code. I gave it a width and a horizontal constraint in the same line of code. So I made 2 different constraint lines for it, one to size it horizontally and one to position it. (same result)

At this point I ran out of ideas. So I deleted my Derived Data folder, and cleaned up my project. (still not working)

Next up I tried printing out the constraints for the problematic view. Using constraintsAffectingLayoutForAxis like so:

println("Horizontal: \(howManyIconView.constraintsAffectingLayoutForAxis(UILayoutConstraintAxis.Horizontal))")

println("Vertical: \(howManyIconView.constraintsAffectingLayoutForAxis(UILayoutConstraintAxis.Vertical))")

and this is what the console prints out:

Horizontal: [<NSLayoutConstraint:0x174299050 H:[UIView:0x17019df60(50)]>]

Vertical: [<NSLayoutConstraint:0x17429aae0 V:|-(0)-[UIView:0x17019df60]   (Names: '|':UIView:0x17019ddc0 )>, <NSLayoutConstraint:0x17429ab30 V:[UIView:0x17019df60]-(0)-|   (Names: '|':UIView:0x17019ddc0 )>]

Unless I'm reading this wrong. It looks like the iconView is only getting a sizing constraint of (50) and not the actual positional horizontal constraint. Despite being put correctly next to my UITextField?

Why this is happening is still a mystery, as far as I can see, my horizontal positioning constraint should be fine. Not getting any errors. But hopefully providing the cause of my problem, will help to get it solved.

Any help would be greatly appreciated! (None of my attempts have caused any errors in the console.)

like image 373
Mark L Avatar asked Mar 18 '15 11:03

Mark L


1 Answers

There are 2 possible errors I see:

  1. I don't see a constraint for contentView left and right. They both should be zero, I believe. Otherwise the position of the contentView will be random in the scrollView. That should be fixed by replacing H:[contentView(contentWidth)] with H:|[contentView(contentWidth)]|

  2. Using self.view.bounds.width for contentView width can be a bit risky - depending from which method you are calling it. Are you sure it's the equal to the size of the screen?

Note that in general it is easier to set up contraints in the Interface Builder because it always warns you about missing constraints.

like image 121
Sulthan Avatar answered Nov 18 '22 06:11

Sulthan