UIStackView with "wrap content" width - ios

Problem:
Create horizontal UIStackView with 2 elements
Item width with "Short text 2" should be "wrap content". Item with "Long text 1" should fill all free space.
Please help to understand, how it can be created in code (Swift language)?

Step 1: Drag a StackView add left, right, top/bottom constraint to it. (ignore error for now)
Step 2: Drag two labels and add it to stackView (continue to ignore warning)
Step 3: Now you need to resolve horizontal content ambiguity so change the content hugging priority of left label to 250 while leaving the right labels content hugging priority at 251
Step 4: Now comes your question of warp content for vertical height :) Simply select the right label and set its content compression resistance to 999 while leaving left label's content compression resistance at 751
If you are wondering whats happening with content compression resistance and content hugging priority and all, please read apple docs on the same for more detail
Just to give a gist of what am doing, in iOS UILabels have implicit content size, so they take size based on content. So is Stack View. Now because StackView has to deduce its height based on two labels it has and both of them have same content compression resistance and end up having different height in order to resolve confusion it looks for further assistance from you. You do that specifying that right label resists more to change in its implicit vertical height compared to left label.
That means now stack view knows that it has to consider right labels height to adjust its height while it can override the implicit size of left label :)
Confirmation of logic:
On changing right label font stack view height automatically increased and increased the height of left label as well :)
EDIT on Comment by OP:
As OP suggested in comment that conern is width and not height, step 4 is not necessary, your problem is resolved at the end of step 3. On setting content hugging priority it self
on changing right labels content UI updates as shown below
Thats all :) Hope that helps

Related

Conflicting constrains with Un-deletable system set constrain

I am trying to add a height constraint to a label so that it doesn't cut off the text that is inside:
However, when I added the height constrain to the label, a conflicting constrain error shows up prompting me to delete one of the constrains, if I just leave this message unsolved, the UI works correctly:
But what confuses me in the error is the fact that the constrain which I had just added seems to be conflicting with an un-deletable constrain height = 0 and I have no idea where is is coming from (The height = 250 is for the stack view):
I could make the error message go away by setting the priority of the label's height constrain lower than 1000, but doing this brings the 'label too small cutting off text' problem right back:
What could be causing this? What I am confused about is:
What is causing the height = 0 un-deletable constrain?
Why is that if I leave this error message unfixed, the UI works as intended?
Thank You for any help!
Tips from Paulw11 for the solution:
I solved the problem by adjusting the label's vertical compression resistance rather than setting a height. I removed the height constrain which removed the error message. In the settings for the stackview, there is a field for "Vertical Content Compression Resistance Priority" (Set to 750 here):
The problem was fixed when the "Vertical Content Compression Resistance Priority" of the label itself was set to a value higher than than that of the stackview's (Set to 1000 here):

How to use stack view to autolayout label and button?

How can I layout a label and a button inside a UIStackView in such a way that the button only takes as much space as it needs and the rest is left for the label? Button text could be various length due to localizations.
The UIStackView here is alignment: center with distribution: fill.The only missing thing here is not stretching the button beyond the width needed for text and insets.
It doesn't seem possible with just the distribution settings. If Fill Proportionally is set the button must have a width constrain . Tried playing with the compression and hugging to no success, maybe I am doing something wrong.
EDIT: Found out why content hugging wasn't working. It needed a value >= 761 and not higher than 250 as I thought. Because 250 is the label content hugging value. Why 761? Can't really say.
You need to set the Content Hugging priority of your button to something higher than 250. That way the button does not want to grow bigger than it needs to.

When can auto layout infer width and horizontal position?

I'm trying to lay out the following simple UI using auto layout:
So far, I've set 5 constraints:
The left edge of the textfield is constrained to the left alignment guide
The top edge of the textfield is contained to the top alignment guide
The right edge of the label is constrained to the right alignment guide
The top edge of the label is constrained to the top alignment guide
The right edge of the textfield is constrained to be 20 points from the leading edge of the label
Based on these constraints, I would think that the width of the textbook would be determined by the size of the label, and horizontal layout for both would be implied. This is indeed how these constraints behave when I change the size of the button, but I'm still receiving the following warning in xcode:
My question is why? Width and horizontal position can be determined by the information provided, and providing additional information (like a fixed width) would only mess with the flexibility of the interface.
Well Width can't be calculated based on the constraints you applied.
Both textField and label grow and shrink based on content.
What will happen If at runtime I add much more text or increase text(content) of both the fields. Then there will be ambiguity about which field to fill full and which to trim.
So one thing need to be fixed based on that other width can be calculated.
You can add one Extra width constraint to Add Activity.
My extra width constraint would be less than or equal to the width you assign. And its priority would be greater than its leading.
Or you would want to play with content hugging priority. With changing content hugging priority one can make it possible for label not to grow.
Cocoa Autolayout: content hugging vs content compression resistance priority
If you don't want to add Extra width constraint Then increasing horizontal hugging of Add Activity to 251 (greater then textfield hugging) will resolve the ambiguous constraint issue.

Equal width and equal spacing between buttons in autolayout

I'm trying to use autolayout constraints to automatically resize a few similarly-sized buttons in a view to give the following effect:
Before resizing
Desired effect after resizing
As you can tell, I want the buttons to be of the same size and I also want the spacing between each button to be a constant 20 points. It seems pretty simple at first, so I set the following constraints:
Buttons: space from left neighbour = 20 (inclusive of left-most and right-most buttons)
Buttons: space from right neighbour = 20 (inclusive of left-most and right-most buttons)
Buttons: same width
What actually happens after resizing
When in preview or when I test run the app in my iPhone/simulator, the button resizes and doesn't even follow the same width constraint I set for it. In fact, the view containing the views also resizes to fit the new button sizes. Anyone knows how to fix this problem purely in the interface builder?
Setting:
- equal widths of all buttons
- horizontal spacing between all buttons
- leading to superview for the first button and trailing to superview for the last button
should do the job. Unless you're having problems with the superview (e.g. ScrollView missing constraints)
In the interface builder you set the spacing constraints between buttons like you described above. Then you can command-select all of them and specify the "Equal Width" constraint to apply to the selected objects.
Finally I have oblivion how to solve this problem. I've test it works like charm.
add constraints to space items with 20 units margin
add constraint to ages
now tricky part
for each item add constraint equal widths to a parent
select all this new constraints and change its properties
set multiplier to value 1:5
set constant to -24 (6 separation between items and parent edge gives 120, this multiplied by multiplier value 1:5 gives 24)
update items frames
That's it! Picture below show how it works in interface builder:
Set simulated size to "freeform" and test different widths (I sett this to 330).
This problem is seems to be because of wrong content hugging priority and content compression Resistance priority. So you should set them as low content hugging and high compression resistance (all should have same value).
Because content hugging is the property that resist a view to grow and content compression Resistance priority is to resist a view to shrink. For more information regarding these you can found this Question.

Label's height issue in tableView with auto layout

I use autolayout. I am displaying 2 labels in custom UITableViewCell. Label1 is above Label2. Their text is dynamic.
The issue is the height of one of the labels when displayed is larger than its text.
I tried changing their Content Hugging Priority.
So what happens is, if that priority is same or Label1's priority is higher, then Label1 is having exact height to fit its text but Label2 has larger hight than required. And when Label2's hugging priority is higher than issue is with Label1's height.
Any idea how to solve it?
It looks like you are expecting your cells to auto-size based on auto-layout's constraint information, but UITableView sizes it's cells using frames/autosizing masks. If this is the expectation and you aren't autosizing the cells like in this question, then your labels are going to either force-clip themselves in order to fit inside the cells with the sizes they were given from the table view or grow to satisfy all of the margin-constraints.
Since the content hugging and content compression resistance priority values are less than required (less than 1000), they are considered "optional" and will be satisfied as close as they can be without violating any of the other required constraints. This is why your label begins growing (or clipping itself).
This can be solved in a couple of ways off the top of my head:
If you don't care about the cell having a variable height and are fine with the labels migrating toward the top of the cell, then make the constraint that pins the bottom label to the lower edge of the superview be non-required. More specifically, make that constraint have a priority lower than the vertical contentHuggingPriority for both of the labels. This way the content hugging priority constraints will take precedence over the lower constraint.
Make your cells auto-size themselves (using auto layout or otherwise) so that the system never has to consider the vertical contentHuggingPriority of each label 'optional'.
I solved this after experimenting with lot of things. The only thing I had to do is to set horizontal and vertical content compression resistance priority to required.i.e. 1000.
I did this for all labels because I don't want any of the labels to trim their content.
One more thing which is too much important is Getting Right Height Of Cell. If there is even 1pt of error in calculating custom cell's height it will not be displayed as expected.
Hint :
If height of any view is greater than expected then possibly calculated height of cell is greater than what is actually required.
If any of views is shrinking vertically or not displaying whole content then possibly calculated height of cell is lesser than what is actually required.
Yoy can test if height is wrong by adding/removing constant value to height (variable) you calculate for cell.

Resources