Autolayout constraints to set labels horizontally - ios

I have a bar with two UILabels:
[LeftMsg RightMsg]
The rules I want to set are:
RightMsg is always fully visible, right-aligned and takes the room it needs.
LeftMsg is left-aligned and takes the remaining room.
For example, if LeftMsg reads "This very long message does not fit the bar", it must be displayed as follows:
[The very long message does n... RightMsg]
I set horizontal auto-layout constrants as follows:
LeftMsg.leading = Superview.leading
RightMsg.trailing = Superview.trailing
LeftMsg.trailing <= RightMsg.leading
(If I use equality in the last constraint, XCode tells that there is a content priority ambiguity).
Now it works as follows:
[The very long message does not fit the...]
that is not what I need.
Can anyone suggest how do I correctly set constraints to achieve what I need?

I think you can set lower horizontal hugging priority for your left label than that of right message label, while at the same time setting higher horizontal compression resistance priority for right message label than that of left message label.
For example, you can set both Content hugging priority and compression resistance priority for your labels like this.
Left Label : content Hugging priority ( H: 250, V: 251)
compression resistance priority ( H: 750, V: 750)
Right Label : content Hugging priority ( H: 251, V: 251)
compression resistance priority ( H: 751, V: 750)
You can see more information about content hugging and compression resistance in this tutorial.

Set the content Compression resistance property of the left label to 750.
Set the Content Hugging Priority of the right label to 250.

Please follow this,
First set both label on View.
Set constraints for View is Top, Bottom,left and Horizontal center
align.
Set constraints for left label is Top ,Bottom,Leading and
Trailing.
Set constraints for Right label is Top ,Bottom and Trailing.
Select both labels and set Equal height and Equal width.
Finished....

Related

Horizontal UIStackView with two label (one multiline label, one one-line)

I have a horizontal UIStackView which has two UILabel in it. First UILabel is multiline (two line) and other one is one line only. They both have default content compression and resistance priorities. My problem is that even there is a gap between labels, "best" word in first text goes second line. I noticed that first label doesn't goes beyond half of total width.
What I want is that second label should always show itself and first label should size It self for remaining space. If It can't fit to one line It should be two line. However, If second label is too short and first label is a long one but both of them can fit, first label should go beyond half of the width.
P.S I need to use UIStackView in this scenario because there are other cases. I know putting two label inside UIView may solve the problem.
UIStackView:
- Distribution: Horizontal
- Alignment: Center
- Spacing: 0
UILabel:
- Number of line: 2
- Line break: Word wrap
UILabel:
- Number of line: 1
View hierarchy:
Desired Result:
OR
EDIT: I calculate the width of second label and give width constraint. I think It solved my problem, I'll test a bit.
//Give specific width to second label to make first one calculate right number of lines.
if let font = UIFont(name: "Metropolis-ExtraBold", size: 15) {
let fontAttributes = [NSAttributedString.Key.font: font]
let size = (secondLabelText as NSString).size(withAttributes: fontAttributes)
secondLabel.widthAnchor.constraint(equalToConstant: size.width).isActive = true
}
To try and simplify...
Forget calculating any widths... what matters is the horizontal Content Hugging and Content Compression Resistance
Leave the left (blue) label at the defaults:
Content Hugging Priority
Horizontal: 251
Content Compression Resistance Priority:
Horizontal: 750
But set the right (orange) label to:
Content Hugging Priority
Horizontal: 1000
Content Compression Resistance Priority:
Horizontal: 1000
Results:
The only other issue would be if the text in the right-side label exceeds the full width of the view -- but you haven't indicated that you might need that much text.
You should set different horizontal content compression resistants for each of them:
For this case, the blue one(multiline) should have something less than the orange one(Singleline).
Assistive note: Multiline: 250, Singleline: 750
Orange Settings:
Blue Settings:
Note that I have set the line limit of the orange one to 0. You can set it to anything you like. But if you like to make it selfsize to anyhight taller view should have higher vertical compression resistant than 250.
First embed your multiline label inside a view and constraint the label to this view (top, leading, trailing, bottom). After that add your view with your multiline label and single line label to your stackView.
Then you can use .fillProportionally for the distribution of your UIStackView and the spacing value to specify the space between your two labels.
Make also sure to use Required (1000) for your horizontal content compression resistance priority on your right number label.
View-hierarchy:
Result:
With spacing between your labels:

Set priority for UIStackView iOS

how can i prioritize a label to be displayed fully and another label to display it too but if its too big it should make ... in the UIStackview
This is my StackView
Here is an example that follows what you want:
First, a UIStackView will actually make things harder here because we want to fine-tune the distance between each label. I just used leading and trailing constraints to layout each label in a line.
The trick is to set the proper content compression resistance priority and content hugging priority for each label. First, we want 0s to always match the size of its content, so we set its content compression resistance priority to 1000. Content hugging priority can stay at the default of 250.
I also split the # sign into its own label, since we always want it to appear. Set its content compression resistance priority to 1000 and keep the content hugging priority at 250.
Next, for the shrink_label, we set the content compression resistance priority to 749 and the content hugging priority to 1000. That is, we want the shrink_label to never try and grow bigger than its text content size, and we want it to allow its content to be compressed if we need.
Finally, for the laaabel we set the content hugging priority to 1000 and the content compression resistance priority to 750. That is, the label will take up as much space as it can, and since its compression resistance priority is 1 higher than the shrink_label's, the shrink_label will compress before the laaabel.
You can read about content compression and content hugging in the Apple docs here:
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/ViewswithIntrinsicContentSize.html
The full source code for my example app is available here:
https://github.com/elliotfiske/StackOverflowContentHuggingExample

How to have two labels side by side, one that can grow, and one cannot?

I have two labels side by side. And I have two constraints set. Label-A starts at the leading edge of the view. Label-B starts 10px from trailing edge of Label-1. There are no width constraints.
Label-A's text length varies; Label-B's text is fixed (6 chars long). This works fine until length of Label-A goes over a certain point. Then Label-B goes off screen.
Before I assign the text value to Label-A, I want to truncate Label-A text with '...' if it will push Label-B beyond the trailing edge of the view. Any idea how to figure out if I should truncate Label-A's text and by how much? This has to work in both portrait and landscape modes.
Thanks.
Set Content Compression Resistance Priority for one of both label, according to your requirement.
Look at these snapshots:
Two labels with default content compression resistance priority.
I changed content compression resistance priority for label blablabla blablabla, from 750 to 749.
Result is:
For more details see Apple document: Setting Content-Hugging and Compression-Resistance Priorities
Make the horizontal content hugging priority and horizontal content compression resistance priority of Label-B higher than Label-A. And also add trailing of Label-B to superview.
First of all make sure that your labels have constraints for leading and trailing.
Your views layout should like this:
|-8-[Label-A]-10-[Label-B]-8-|
After that set the horizontal content hugging priority and the horizontal compression resistance of Label-B higher than Label-A.

Arranging two side-by-side items in a Table View cell

Each row in a table (UITableView) consists of two elements: label and value.
Value is right-aligned and is wide enough to hold the text without wrapping. Label is left aligned and takes all the width remaining after value (with a small margin). It allows text wrapping.
UIStackView (horizontal) appears to be the one, but I couldn't find a way to say: 'this takes as much as needed, and that takes all the rest'.
Is there a solution without coding ?
Update. After suggestion by Mr Bista, I've made the following:
StackView:
Alignment: Fill
Distribution: Fill
Content Mode: Scale to Fill
Constraints: leading: leadingMargin, trailing: trailingMargin
Label:
Alignment: Left,
Line Break: Word Wrap,
Lines: 0
Content Hugging Priority: 251 Both
Content Compression Resistance Priority 750 Both
Value:
Alignment: Right,
Line Break: Truncate Tail,
Lines: 1
Content Hugging Priority: 251 Both
Content Compression Resistance Priority
751 Horizontal, 750 Vertical
The fields are spaced equally both with distribution Fill or Fill Equally (top image). With "Fill Proportionally" I lose Value at all (bottom image). Maybe, I am missing something?
Set the Content Compression Resistance Priority of value label to 751 i.e 1 more than Label Label 750.
Also set the Alignment and Distribution of Stack View to Fill.

How fill a UITableViewCell with multiple UILabel using auto layout

i have a UITableViewCell that contains some UILabel and i want that this label fill horizontally the width of the UITableViewCell and that doesn't remains big space instead of other, this is an example:
|---------------------------------------------------------
| |
|***This is a uilabel***This is a uilabel***label***lb** |
| |
|---------------------------------------------------------
So with different UILabel width i want that all the UILabel fill all the UITableViewCell fixing the font size if needed, the * is the spacing, how i can achieve this with auto layout?
STEP 1: Set up constraints
Leftmost label: Add a leading edge constraint and a center Y constraint to its superview
Middle labels: Add a horizontal spacing and center Y constraint to previous label.
Rightmost label: Add a horizontal spacing and center Y constraint to previous label plus a trailing edge constraint to superview.
These constraints ensure the gaps between the labels and on the left and right are fixed in size, and that they are all centered in their superview. Because there are no width constraints, the layout system will attempt to size them to fit their content. But this leaves an ambiguity...
STEP 2: Set content size priorities.
The above constraints are still ambiguous -
If the total text content is less than the superview's width, which label will expand bigger than its content?
If the total text content is more than the superview's width, which label will contract shrinking its content to fit?
The answer to the first question is the label with the lowest horizontal content hugging priority. By default they will all have the same, so make sure they have different horizontal content hugging priorities.
The answer to the second question is the label with the lowest horizontal content compression resistance priority. By default they will all have the same, so make sure they have different horizontal content compression resistance priorities.
STEP 3: Ensure text shrinks to fit.
We now have an unambiguous layout. But by default, the labels will truncate their content if they do not have room to display it. Set Autoshrink to Minimum Font Scale or Minimum Font Size on your labels to ensure they adjust font size to fit their content rather than truncating it.

Resources