iOS Dynamic Sizing Labels

ios Dynamic sizing labels

You can calculate the size of in which your string will appear and then can set frame of your UILabel to that size see following code as a sample -

//Calculate the expected size based on the font and linebreak mode of your label
CGSize maximumLabelSize = CGSizeMake(296,9999);

CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font
constrainedToSize:maximumLabelSize
lineBreakMode:yourLabel.lineBreakMode];

//adjust the label the the new height.
CGRect newFrame = yourLabel.frame;
newFrame.size.height = expectedLabelSize.height;
yourLabel.frame = newFrame;

Update -

Use sizeWithAttributes: instead, which now takes an NSDictionary. Pass in the pair with key UITextAttributeFont and your font object like this:

CGSize size = [string sizeWithAttributes:
@{NSFontAttributeName:
[UIFont systemFontOfSize:17.0f]}];

Check Replacement for deprecated sizeWithFont: in iOS 7? for more details

Creating a dynamically sizing UILabel in the Xcode interface builder

You can do this with 3 constraints:

  1. center the label horizontally in the view
  2. set a width constraint of <= 500
  3. set a leading space constraint of 16. Give this a priority of < 1000.

When the view is wide (like on an iPad), the label will stretch to its full width of 500. Auto Layout will keep the label centered, and it will try its best to satisfy the 3rd constraint by keeping the the leading space as close to 16 as possible. It chooses to break this constraint because the priority is less than 1000.

When the view is narrow (like on an iPhone), the label will have a leading space of 16 (and trailing space of 16 because the label is centered). The width will be whatever is left, because that satisfies the width <= 500 constraint.

Constraints for dynamically size uilabel width programmatically

lessThanOrEqualToConstant for the widthAnchor should do the job.

let labelOne = UILabel()
labelOne.text = "label1"
let labelTwo = UILabel()
labelTwo.text = "label2"

labelOne.translatesAutoresizingMaskIntoConstraints = false
labelTwo.translatesAutoresizingMaskIntoConstraints = false

view.addSubview(labelOne)
view.addSubview(labelTwo)

NSLayoutConstraint.activate([
labelOne.topAnchor.constraint(equalTo: view.topAnchor),
labelOne.leadingAnchor.constraint(equalTo: view.leadingAnchor),
labelOne.widthAnchor.constraint(lessThanOrEqualToConstant: 100),

labelTwo.leadingAnchor.constraint(equalToSystemSpacingAfter: labelOne.trailingAnchor, multiplier: 1),
labelTwo.topAnchor.constraint(equalTo: view.topAnchor)
])

Adjust UILabel height depending on the text

sizeWithFont constrainedToSize:lineBreakMode: is the method to use. An example of how to use it is below:

//Calculate the expected size based on the font and linebreak mode of your label
// FLT_MAX here simply means no constraint in height
CGSize maximumLabelSize = CGSizeMake(296, FLT_MAX);

CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font constrainedToSize:maximumLabelSize lineBreakMode:yourLabel.lineBreakMode];

//adjust the label the the new height.
CGRect newFrame = yourLabel.frame;
newFrame.size.height = expectedLabelSize.height;
yourLabel.frame = newFrame;

what scenarios of layout design needs Dynamic height label and a text field next to each other?

Even though your question is a little unclear, let's see if this helps explain things...

Suppose we start with 2 labels - LabelA (green) and LabelB (cyan):

Sample Image

LabelB is constrained 20-pts below LabelA... as we add text to LabelA, it will grow in height, "pushing" LabelB down and keeping the 20-pts vertical spacing:

Sample Image

Sample Image

Sample Image

All of that is pretty simple, and it's exactly what we expect to happen.

But, suppose we want LabelB to start at 100-pts from the top of the view (the safe-area), and only move down if LabelA gets tall enough?

If we add a Top constraint to LabelB, that will stretch LabelA:

Sample Image

Or, it will compress LabelA:

Sample Image

In both cases because LabelB Top cannot be both 100-pts from the view Top AND 20-pts from LabelA Bottom at the same time.

So, let's change LabelB Top to at least 20-pts from LabelA bottom, by setting it to >=, and, we'll change the LabelB Top constraint to a priority of less-than-required. In this example, we'll use Default High (750).

What we've done is told auto-layout to break the 100-pt Top constraint if needed. So, if LabelA is short, LabelB can be at 100-pts, but if LabelA gets tall, keep LabelB 20-pts below LabelA and break the 100-pt Top constraint:

Sample Image

Sample Image

Sample Image

Sample Image

So, it's not so much the order in which the constraints are evaluated, as it is the logical ability for auto-layout to satisfy all the constraints.


Edit

To try and explain the specific example from Apple...

Let's start with a minimum set of constraints, where the fonts are:

Label - 30pt
Field - 14pt

Sample Image

The Name Label is 40-pts from the Top, and the Name Text Field is constrained to the FirstBaseline of the label.

Now let's change the fonts to this:

Label - 20pt
Field - 30pt

so the Field is taller than the Label, here's what we get:

Sample Image

The Top of the label is still 40-pts from the Top, but the field has been moved up (to maintain the baseline alignment) and the Top of the field is now only (about) 25-pts from the Top.

The goal is to keep the Top of tallest element at 40-pts. With only these two vertical constraints, as we can see, we failed.

So, let's reset the fonts to:

Label - 30pt
Field - 14pt

and add the additional constraints with specified Priorities:

Sample Image

The positioning is identical to the first example, but... if we again change the fonts to:

Label - 20pt
Field - 30pt

this is the result:

Sample Image

The Top of the field is at 40-pts, and the Top of the label has moved down (to maintain the baseline alignment).

And... we've accomplished our goal!


Edit 2

To try to clarify with "plain language"...

The Baseline constraint will control the relative vertical alignment of the two elements. As we change the font size of one, it will make that element "taller" (or "shorter") and the other element will move vertically to keep the baselines aligned.

We've added a required constraint of top >= 40 to each element. That tells auto-layout "don't let either element be closer than 40-pts from the top."

We've added a constraint of top = 40 to each element, with Priority: 249. That tells auto-layout "try to put the top of each element at 40-pts... if you can't (because the baseline alignment is pulling it down), then go ahead and break that top constraint."



Related Topics



Leave a reply



Submit