Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide a UILabel when there is not enough space to display the full text with autolayout

I have a horizontal stack view with three controls from left to right: a custom UIView subclass (which has an intrinsic content size), and two UILabels. Both labels are configured like this:

label.numberOfLines = 1
label.adjustsFontSizeToFitWidth = false
label.adjustsFontForContentSizeCategory = true

I set the stack view distribution to .fill and the content hugging priority and content compression resistance priority of the three controls such that the custom view and first label's frames hug the content and the second label stretches to fill the remaining space. It looks like this:

|[custom view][label 1][label 2     ]|

My issue comes when I adjust the system text size to be larger such that there is not enough horizontal space to display the full text of both labels. Instead of truncating the text of the first label with "...", I would like for it to be hidden entirely when there is not enough space to display the full text. Is there any way to do this with autolayout?

It feels as though there should be a way to do this with a width = 0 constraint with a priority carefully calibrated around the compression resistance priority, but I can't quite wrap my brain around how to do it.

like image 661
jjoelson Avatar asked Jul 04 '17 16:07

jjoelson


1 Answers

So ultimately I wasn't able to find a way to do this using Auto Layout. From what I can tell, AL doesn't allow you to use low-priority constraints to define a fallback layout. Rather, low-priority constraints exist to clarify how things should be laid out when the required and higher-priority constraints leave extra leeway.

Instead, I realized that this makes more sense as a behavior of the label, as UILabel already implements a number of behaviors for when the text doesn't fit: it can shrink the font, clip, or truncate in various ways. So it makes sense to subclass UILabel and add the behavior there. Here's the code:

class HidingLabel: UILabel {
    override func layoutSubviews() {
        super.layoutSubviews()

        if bounds.size.width < intrinsicContentSize.width {
            frame = CGRect.zero
        }
    }
}
like image 84
jjoelson Avatar answered Nov 14 '22 01:11

jjoelson