How to use stack view to autolayout label and button? - ios

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.

Related

Strange behavior of custom UITableViewCell label

I don't know why, but my label behaves strangely. You can check screenshots bellow. Image should fill stackView.
Screenshots
Since you really ought to share a bit more, I can only try to answer based on what's available.
The problem is most likely due to the fact that the StackView that surrounds the label and image does not have a width or height constraint of any sort and/or the imageView has a very low content compression resistance property.
Because StackViews calculate their size based on their child views, it will try to find the best fit. If the label has a normal compression resistance but the imageView has its resistance set to low, the stackView will simply calculate its frame based on the label alone.
So to fix it check the compression resistance of those objects or define contraints for the surrounding stackView to match its parents width.
Firstly.. What is it that you are trying to achieve? Image and Text one beside the other, or one below the other? You might want to check for the stackview direction property
Secondly if you want that your image size remains constant, you will have to give your image view some fixed width constraint, and stackview will respect the size of the imageview. Or if you want that the image takes the entire width of the screen, you can basically pin the stackview to the edges of the screen, after you have put in the imageview inside of the stackview.
Hope that makes sense.
Comment back if you need more help :)

UIStackView with "wrap content" width

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

adding nearest neighbour constraints to a NStextfield causes it to shrink to the size of the text

Edit: I found the correct solution and will include it at the bottom of the question
I have a textfield. I constrain the textfield to nearest neighbour, which is in this case the view and when i do this, height for the textfield goes out of my control and matches the size of the text exactly. How can I constrain the text box to nearest neighbour without the text box automatically resizing. Below is an image that shows my constraints and the orange outline of what the textfield wishes to resize to. It also shows that the view will shrink to an expected height of 62 aka the size of the text box.
I would add, that when i checked the constraints in inspector, i found that the text box was not always set to first items. when I made the text box the first item in all constraints the width became editable.
Answer:
1) The secret to adding constraints to a text box it to put content hugging as a low priority eg. 250. Look at the above picture and you can see content hugging vertically is at 750 or high priority while content hugging horizontally is at low priority(=250). Therefore i am able to constrain to nearest neighbor for the width which is at low priority but not for the height which is at high priority.
For more info check this documentation
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithConstraintsinInterfaceBuidler.html#//apple_ref/doc/uid/TP40010853-CH10-SW2
2) each constraint has a first and second item in the inspector. The second item gets its attributes(eg. size) from the first. double click on the contraints in the size inspector as pictured above to inspect the constraint more closely
The layout engine does not know what size you want the parent view (your view controller in this case), so it takes the intrinsic content size of the textfield.
Do you want the textfield to be exactly as big as it needs to be? Then don't touch it, your textfield will resize to contain the text, using your constraints to place itself.
Do you want your view controller to have a certain size? (e.g. if you want a specific background image to fit) Then you might want to consider adding constraints to your parent view so that it keeps a certain size or aspect ratio.
I will suggest to remove existing constraints, and add vertically and horizontally center constraints.

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.

Resources