2

I'm trying to simulate a kind of "Please wait..." UILabel. The label's text must be regularly updated. So far everything works as expected. However, I need to get the intrinsic content height of the label to be able to position its container view (UIView).

enter image description here

The label is the one with the red background, whereas the one with the white background is its container.

I've tried a few different approaches, unfortunately, all in vain. Any help would be greatly appreciated.

private func createBusyLabel(labelText: String) -> CGFloat {

    self.busyViewContainer.addSubview(self.busyLabel)

    self.busyLabel.backgroundColor = UIColor.red

    self.busyLabel.numberOfLines = 0
    self.busyLabel.lineBreakMode = NSLineBreakMode.byWordWrapping
    self.busyLabel.sizeToFit()

    //set the constraints, but skip height constraints
    self.busyLabel.translatesAutoresizingMaskIntoConstraints = false
    self.busyLabel.horizontalLeft(toItem: self.busyViewContainer, constant: 60)
    self.busyLabel.horizontalRight(toItem: self.busyViewContainer, constant: -10)
    self.busyLabel.topConstraints(toItem: self.busyViewContainer, constant: 10)


    self.busyLabel.text = labelText
    //calculate height with margin
    let height: CGFloat = self.busyLabel.intrinsicContentSize.height + 20
    return height

}

Also, the line counting function, from a previously asked and already answered question, delivers only 1

Here is what it look like after I set the bottom constraint:

enter image description here

Community
  • 1
  • 1
Odd
  • 563
  • 8
  • 20
  • Is there a reason why you haven't set any bottom constraint? – Ozgur Vatansever Apr 03 '17 at 13:10
  • Yes, you need to set a bottom constraint. Also you should use leading and trailing constraints rather than left/right – Paulw11 Apr 03 '17 at 13:13
  • Hi Ozgur, I did not consider bottom constraint, as to me it did not really make any sense. Am I wrong? – Odd Apr 03 '17 at 13:15
  • Hi Paulw11, the horizontalLeft/Right are leading and trailing constraints. How could I set the bottom constraint? I need some reference point to set the bottom constraint. – Odd Apr 03 '17 at 13:17
  • What constraints do you have on the container view? You need to ensure you haven't constrained the height of this view, either implicitly or explicitly, to allow it to grow to contain the label. – Paulw11 Apr 03 '17 at 13:58
  • , the container should have constraints to its super view on it's left and right and on its top **or** centery-y **or** bottom but not its height. – Paulw11 Apr 03 '17 at 14:07

2 Answers2

1

A million Thanks to ozgur, who changed my approach. Ozgur, your code works perfect, but unfortunately not for me, as I faced problems with bottomLayoutGuide part. The reason for this is that the label and its container are created in an external class.

Previously I tried to set bottom constraint to the label, which did not return the expected result. However, inspired by ozgur's answer, this time I simply set the bottom constraint to its container and not the label, giving in expected result, like following:

    self.busyViewContainer.bottomConstraints(toItem: self.busyLabel, constant: 10)

Thanks to all who put in their precious efforts.

private func createBusyLabel(labelText: String) -> Void {

    self.busyLabel.text = labelText
    self.busyLabel.font = UIFont.getGlobalFont(size: _textSizeSmall, type: "bold")

    self.busyLabel.backgroundColor = UIColor.red

    // handle multiline problem
    self.busyLabel.numberOfLines = 0
    self.busyLabel.lineBreakMode = NSLineBreakMode.byWordWrapping
    self.busyLabel.sizeToFit()

    self.busyViewContainer.addSubview(self.busyLabel)
    self.busyLabel.translatesAutoresizingMaskIntoConstraints = false
    self.busyLabel.horizontalLeft(toItem: self.busyViewContainer, constant: 60)
    self.busyLabel.horizontalRight(toItem: self.busyViewContainer, constant: -10)
    self.busyLabel.topConstraints(toItem: self.busyViewContainer, constant: 10)

    // the following line made the difference
    self.busyViewContainer.bottomConstraints(toItem: self.busyLabel, constant: 10)

}

enter image description here

Odd
  • 563
  • 8
  • 20
0

The simple fix is adding the bottom constraint between 'self.busyViewContainer' and its superview.

Following your code and syntax it can be something like this:

self.busyLabel.bottomConstraints(toItem: self.busyViewContainer, constant: 10)

It is a common problem with 'Unsatisfiable Constraints'. The autolayout should ensure it satisfies horizontal axis layout so it needs to have both top and bottom constraints in this case.

Apple doc - Unsatisfiable Constraints

Apple doc - Logical Errors

UPD: In this case, the layout of the superview can define a height with intrinsicContentSize:

var intrinsicContentSize: CGSize { return ... }

Where the height of the parent view will be calculated based on the label one.

Yuri
  • 459
  • 5
  • 13
  • Hi Yuri, thanks at first. I tried your suggestion, but this does not seem to solve the problem, as the bottom constraint could only be set after the height of the parent container is set (in this case self.busyViewContainer) – Odd Apr 03 '17 at 13:38
  • In this case, you can subclass the busyLabel And in this class override the - (CGSize)intrinsicContentSize to respect the label height based on text. – Yuri Apr 03 '17 at 13:44
  • Basically, using '-(CGSize)intrinsicContentSize' will change the label height accordingly and you won't need to return a height as a function (''func createBusyLabel(labelText: String) -> CGFloat") – Yuri Apr 03 '17 at 13:47
  • Hi Yuri, I deeply appreciate your efforts. I don't quite understand your point. May I request for some practical example. – Odd Apr 03 '17 at 13:58
  • How do you use the results of this function func createBusyLabel(labelText: String) -> CGFloat? The label height needs to be higher priority and its superview should have constraints defining the height. So it will calculate its height based on its content. – Yuri 1 min ago edit – Yuri Apr 03 '17 at 14:06