Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set a label's preferredMaxLayoutWidth to automatic programmatically?

I get the following errors when I attempt to set a label's Preferred Width to Automatic in a storyboard:

Attribute Unavailable: Automatic Preferred Max Layout Width is not available on iOS versions prior to 8.0

Since I need my layout to work on both iOS 7 and 8, I was planning to do the following:

  1. Set the value to Explicit in the storyboard.
  2. On iOS 7, set the value to an explicit, computed width programatically.
  3. On iOS 8, set the value to automatic programatically.

1 and 2 are easy. How do I do step 3? Is there a constant I can set it to?


Here's what I have tried so far...

If you set the value to automatic on a storyboard and you inspect preferredMaxLayoutWidth, you will see that it is 0.

However, attempting to set it to 0, even if it says it is already 0, doesn't work properly (e.g. the label stays as a single line). For example, I tried setting the value to automatic in the storyboard, and on viewDidLoad, I ran the following:

self.label.preferredMaxLayoutWidth = self.label.preferredMaxLayoutWidth;

When I don't run the above code, the label is sized properly. However, when I run the above code (which should do nothing), it stays as a single line (undesirable behavior).


The header file for UILabel says:

// Support for constraint-based layout (auto layout)
// If nonzero, this is used when determining -intrinsicContentSize for multiline labels
@property(nonatomic) CGFloat preferredMaxLayoutWidth NS_AVAILABLE_IOS(6_0);

As far as a constant, I couldn't find anything. The closest constant I can think of to what I want is UITableViewAutomaticDimension, which doesn't work.

Here is what the storyboard looks like....

Automatic layout width:

<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" text="Foo" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Bis-iG-g4l">
    <rect key="frame" x="20" y="116" width="560" height="21"/>
    <fontDescription key="fontDescription" type="system" pointSize="17"/>
    <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
    <nil key="highlightedColor"/>
</label>

Explicit layout width:

<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" text="Foo" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="560" translatesAutoresizingMaskIntoConstraints="NO" id="Bis-iG-g4l">
    <rect key="frame" x="20" y="116" width="560" height="21"/>
    <fontDescription key="fontDescription" type="system" pointSize="17"/>
    <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
    <nil key="highlightedColor"/>
</label>

The only difference is that the latter has:

preferredMaxLayoutWidth="560"
like image 741
Senseful Avatar asked Dec 30 '14 20:12

Senseful


1 Answers

I haven't figured out a way to do this programmatically, but there is a pretty decent workaround.

Any valid workaround must meet these requirements:

  • Use automatic preferredMaxLayoutWidth on iOS 8, and explicit on iOS 7.
  • Must not have warnings.

The only way to set preferredMaxLayoutWidth to automatic is via a storyboard, so we do so.

In order to suppress the above warning, set the number of Lines to 1.

Now, programmatically, do the following:

self.label.numberOfLines = 0;
if (iOS8) {
    ; // do nothing, it will use automatic via the storyboard
} else {
    self.label.preferredMaxLayoutWidth = screenWidth - 32;
}

For reference, here is how to find out the iOS version, and here is how to get the screen width. Note that you must specifically look for iOS 8 and not whether or not the object responds to preferredMaxLayoutWidth, since that property was added in iOS 6.

like image 168
Senseful Avatar answered Sep 19 '22 22:09

Senseful