Search code examples
iosswiftuilabel

preferredMaxLayoutWidth not working in Swift?


I have tried to make a UILabel that is a certain width using preferredMaxLayoutWidth but no matter what I do it won't work. Can you help me? I have tries so many different combinations to make it work.

@IBAction func addBottomTextButton(sender: AnyObject) {

   if addBottomTextField.text.isEmpty == false {
      let halfScreenWidth = screenSize.width * 0.5
      let bottomScreenPosition = screenSize.width
      memeBottomText = addBottomTextField.text
      fontName = "Impact"
      let memeBottomTextCaps = memeBottomText.uppercaseString // --> THIS IS A STRING!

      labelBottom.text = memeBottomTextCaps
      labelBottom.textColor = UIColor.blackColor()
      labelBottom.textAlignment = .Center
      labelBottom.font = UIFont(name: fontName, size: 32.0)
      labelBottom.sizeToFit()

      labelBottom.userInteractionEnabled = true
      labelBottom.adjustsFontSizeToFitWidth = true
      labelBottom.numberOfLines = 1
      labelBottom.preferredMaxLayoutWidth = screenSize.width
      labelBottom.setTranslatesAutoresizingMaskIntoConstraints(true)

      var r = CGFloat(halfScreenWidth)
      var s = CGFloat(bottomScreenPosition)
      labelBottom.center = CGPoint(x: r, y: s)

      self.view.addSubview(labelBottom)
      self.view.addConstraint(NSLayoutConstraint(item: labelBottom, attribute:
         NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: labelBottom,     
         attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0))

      dismissKeyboard()
   }
}

Solution

  • Judging by your code I'd say your problem was you haven't got your constraints setup correctly and you're mixing using NSLayoutConstraints with setting the position using center and setting the size using sizeToFit.

    Firstly, in the constraint you've setup you're relating labelBottom (the item argument) to itself (the toItem argument). I'm not exactly sure what you were trying to achieve with that? I'd recommend having a look at some tutorials on AutoLayout if you're unfamiliar with its concepts. Here's a good one: http://www.raywenderlich.com/50317/beginning-auto-layout-tutorial-in-ios-7-part-1

    Secondly, just a small point, on the line let memeBottomTextCaps = memeBottomText.uppercaseString you've written // --> THIS IS A STRING. An easier way to remind yourself of the variable type when looking back at your code could be to use: let memeBottomTextCaps: String = memeBottomText.uppercaseString.

    Thirdly, preferredMaxLayoutWidth isn't used to set the width of a UILabel - that's what the frame is for (or NSLayoutConstraints if you're using AutoLayout).

    Lets get on with it!

    Here's an example of how to create a label that is pinned to the bottom edge of its container view and is not allowed to be wider than it's container: (Keep in mind that all this can be done in IB)

    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let label = UILabel()
            // 1.
            label.setTranslatesAutoresizingMaskIntoConstraints(false)
            // 2.
            label.text = // Put your text here.
    
            // 3.
            self.view.addSubview(label)
    
            // 4.
            let pinToBottomConstraint = NSLayoutConstraint(item: label,
                attribute: .Bottom,
                relatedBy: .Equal,
                toItem: self.view,
                attribute: .Bottom,
                multiplier: 1.0,
                constant: -8.0)
    
            // 5.
            let horizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("|-8-[label]-8-|",
                options: .DirectionLeadingToTrailing,
                metrics: nil,
                views: ["label" : label])
    
            // 6.
            self.view.addConstraint(pinToBottomConstraint)
            self.view.addConstraints(horizontalConstraints)
        }
    }
    

    The following referrers to the commented numbers in the code above.

    1. You need to set setTranslatesAutoresizingMaskIntoConstraints to false to stop constraints being created that would otherwise conflict with the constraints we're going to create later. Here's the what Apple have to say about it:

    Because the autoresizing mask naturally gives rise to constraints that fully specify a view’s position, any view that you wish to apply more flexible constraints to must be set to ignore its autoresizing mask using this method. You should call this method yourself for programmatically created views. Views created using a tool that allows setting constraints should have this set already.

    2. You need to make sure you put your own text here, otherwise the code won't run.

    3. The label must be added to the view hierarchy before adding constraints between it and it's superview! Otherwise, in this case, you'll get a runtime error saying:

    Unable to parse constraint format: Unable to interpret '|' character, because the related view doesn't have a superview |-8-[label]-8-|

    This is due to our horizontalConstraints needing to know the label's superview (the superview is denoted by the "|") but the label doesn't have a superview.

    4. The pinToBottomConstraint constraint does what it says. The constant of -8 just specifies that I want the label to be 8 points from the bottom of its container view.

    We don't need to create a constraint to specify the label's size - that's an intrinsic property of the UILabel which is determined, for example, by the number of lines and font.

    5. The horiontalConstraints are created using Visual Format Language. Here's a good tutorial: http://code.tutsplus.com/tutorials/introduction-to-the-visual-format-language--cms-22715 Basically, "|-8-[label]-8-|" creates constraints to pin the left and right edges of the label to the left and right edges of its superview.

    6. Finally add the constraints!

    This is what it looks like:

    enter image description here

    I hope that answers your question.