iOS Constraints: how to give UILabel height constraint priorities - ios

I have following problem:
I have a view with fixed height. In this view, there are two singleline UILables. The view is bigger than both of the labels so I want them to be displayed like this:
I added three constraints to achieve this:
first label top to view top
second label top to first label bottom
second label bottom to view bottom
(if you want to, i can add the code for this but I think its quite obvious)
So now the problem is following. Sometimes the view renders as intended, but somtimes it renders differently:
The behaviour is quite random.
I think it is because, both UILabels have a (autogenerated) height constraints with the same priority. And sometimes, the first label gets the correct size, sometimes the second label gets it.
So is there a way to change the priority of those autogenerated height constraints or another way to achieve this layout?
(I don't want to use a containerview for the second UILabel)
best regards

Your constraints are ambiguous, hence the random result. You haven't specified how the height should be used.
You should specify this by setting the vertical hugging priority of the top label to a value higher than the vertical hugging of the bottom label.

Related

NSLayoutContraints: How to position a bottom view below the higher of two labels?

I am working on an iOS 11+ app and would like to create a view like in this picture:
The two labels are positioned to work as columns of different height depending on the label content. The content of both labels is variable due to custom text entered by the user. Thus I cannot be sure which of the the two labels is higher at runtime and there is also no limit to the height.
How can I position the BottomView to have a margin 20px to the higher of the two columns / labels?
Both labels should only use the min. height necessary to show all their text. Thus giving both labels an equal height is no solution.
I tried to use vertical spacing greater than 20px to both labels but this leads (of course) to an Inequality Constraint Ambiguity.
Is it possible to solve this simple task with Autolayout only or do I have to check / set the sizes and margins manually in code?
You can add labels to stackView
One way to do this is to assign equal height constraint to both label. By doing this height of label will always be equal to large label (Label with more content).
You can do this by selecting both labels and adding equal height constraint as mentioned in screen short.
Result would be some think like below
The answer given as https://stackoverflow.com/a/57571805/341994 does work, but it is not very educational. "Use a stack view." Yes, but what is a stack view? It is a view that makes constraints for you. It is not magic. What the stack view does, you can do. An ordinary view surrounding the two labels and sizing itself to the longer of them would do fine. The stack view, as a stack view, is not doing anything special here. You can build the same thing just using constraints yourself.
(Actually, the surrounding view is not really needed either, but it probably makes things a bit more encapsulated, so let's go with that.)
Here's a version of your project running on my machine:
And with the other label made longer:
So how is that done? It's just ordinary constraints. Here's the storyboard:
Both labels have a greater-than-or-equal constraint (which happens to have a constant of 20) from their bottom to the bottom of the superview. All their other constraints are obvious and I won't describe them here.
Okay, but that is not quite enough. There remains an ambiguity, and Xcode will tell you so. Inequalities need to be resolved somehow. We need something on the far side of the inequality to aim at. The solution is one more constraint: the superview itself has a height constraint of 1 with a priority of 749. That is a low enough priority to permit the compression resistance of the labels to operate.
So the labels get their full height, and the superview tries to collapse as short as possible to 1, but it is prevented by the two inequalities: its bottom must be more than 20 points below the bottom of both labels. And so we get the desired result: the bottom of the superview ends up exactly 20 points below the bottom of the longest label.

How to set stack view height according to its subviews height?

I have a requirement to scroll six different type of view, Each view has different size, One of the views is: About Me. In About Me, I have to show the title (i.e. ABOUT ME) and text below it and label height should be according to text height.
Till Now I have designed this requirement as:
Root View
- Stack View
* Item 1 with fix height
* Item 2 with fix height
* UIView as About Me:
- Label as title
- Label as text with max lines set to 0 and width equals to container width.
The problem is: I can not set fix height of about me UIView and it does not resize according to label text.
Please suggest the appropriate solutions.
Hi you can get the intrinsic height of the stackView like this:
let size = stackView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
I know Im kinda late to reply to this message. But I had the same issue and I found this piece of code. Thought anyone who looking for this might be useful :)
I don't think that you declare your problem clearly. The first thing I want to point out is that UIStackView can infer its size by the size of its arranged subview. But you must first confirm that the constraints added to the subviews are proper. So if you don't get the resizing effect you want, you must be missing something. Maybe you're not making the reasonable constraints.
To clarify your situation, you'd better add some screenshot of your constraints added to your 'About Me' view. By the way, what's the axis of your UIStackView?
I don't know either of these. So I have to make some assumption for me to explain more about your problem.
The axis of your UIStackView is UILayoutConstraintAxisVertical.
And your UIStackView(or all of your content) has a fixed width.
With the above conditions, Defining a view that its height is decided by its text will be simple. Because UILabel doesn't have to have a fixed size. You only need to specify its width(or specify its leading and trailing to its superview), and its height will be automatically computed based on its font and content.
Your About Me view has two label, so you should
Make sure of these things:
Title label: The top, leading, trailing constraints to the super view. and the bottom gap to the subtitle label(whatever you call).
Subtitle label: The leading, trailing, bottom, constraints to the super view. and the top gap to the title label.

Greater than or equal constraint not working correctly

I have a UIView with 3 UIViews inside, I need every UIView to define it's one height depending of its contents and at the same time, the parent view should change its size depending of its children. But I'm having this issue:
I need the first UIView from the second column's height to always stick to its content and leave the remaining space in the end of the column. In other words, what I want is the second column's first UIView to shrink.
Here's my IB, the greater than or equal constraints are not working as I expected (I highlighted the relevant constraints):
I've tried changing priorities but nothing's working, hope you can help me out, thanks.
EDIT: I forgot to show what's going on inside each UIView. The image might be present or not so if it's not I remove it and "pass" the UIView's height responsibility to the label, just that:
A greater than or equal constraint will always be as small as possible while satisfying all other constraints. So in this case it is correct...
The reason it is correct is because the label you are using will allow its frame to grow beyond its content.
To fix this you need to change the content hugging priority on the two labels on the right hand side.
To do this, select the label and go to the measurements section in Interface Builder property inspector.
Near the bottom you will see "Content Hugging Priority". Change the vertical value of this to 1000 (a.k.a. required).
This will tell the label to keep its frame as small as possible to fit the content. And so, the greater than constraint will have to be taller to satisfy this.
I got it working by extending the labels to the bottom of each UIView, now the UIViews have no excuse to expand more than the label's height.

UIScrollView with multiple multi-line labels and AutoLayout?

Is there a way to achieve this? I have tried literally everything and nothing has worked for me yet.
So basically what i want to do is the following: I have a scroll view with some labels in it. All the labels get their text from a server and I have set their number of lines to 0 so that they change their height according to the amount of text. However, this does not affect the scrollview content size(even though my labels have constraints set up to the bottom,top,leading and trailing of the scrollview) and the labels go off screen and I am unable to scroll down. Can someone point me in the right direction to how I would set up my constraints, my view hierarchy and etc?
Any help is much appreciated! :)
Late, but this solved it for me:
Set leading (I have a 32pt inset), trailing and top constraints. The trailing will not actually seemingly do anything..
Make the trailing Greater Than or Equal to avoid localization alert.
Finally, add a new Equal Width constraint to the label matching the scrollview. Use the constant to subtract the required padding (I used 64 due to mirror my leading inset).
And voilĂ ! The Label will align correctly both in IB and in-app.
In Scrollview the last view's bottom constraint is so important. You should set its priority to 250 and put it to Greater than or equal.
Remember you should only change the bottom constraint of the last view, which in my case it's the continue button.
I would consider using UITableView instead, it has several benefits:
It allows for reuse of cells, if all the cells look the same
It manages recycling of cells when the number of values you're getting from the server increases (decreases memory pressure when number of cells becomes substantial)
It allows for more flexibility with the content (it's quite often for design to change last second or to evolve over the course of the project)
Most importantly, UITableView support auto sizing cells (as of iOS8), you need to specify the constraints between the label and the borders of the cell
There are several resources to start with:
http://www.raywenderlich.com/73602/dynamic-table-view-cell-height-auto-layout
https://www.captechconsulting.com/blogs/ios-8-tutorial-series-auto-sizing-table-cells
http://www.appcoda.com/self-sizing-cells/
Use a container view in a scrollView
Add constraints to superview (leading, trailing, top, bottom, height,width)
Make IBOutlet of constraints that you are going to update.
Add you all labels inside that view.
Update constrains/frame of your label so that it fits the text.
How much you increase the label height you should increase the container height too.
If the label count is not fixed use custom label class to add subview.
Perhaps you should need to understand how ScrollView works in Storyboard with autolayout.

How to change uiview's height using auto layout?

So I created this scenario in order to understand how views increase in height according to their content. However am still not able to make it happen.
This is what I have now:
the textview is growing according to content. however the uiview containing it is disappearing. what constraints should I use so that when the uitextview becomes bigger, its parent view also increase in height?
Start by clearing all your constraints from everything so we have a fresh slate.
Step 1: Build your view hierarchy. In this example, we want something like this:
The view controller's view, which we'll call parentView has a subview, which we'll call redView. That redView has a child, a Text Field, which we'll call textField.
The hierarchy looks like this:
Step 2: Set any constraints that are specific to any individual view. In this case, we probably only want to set a width constraint on our text view. For now, I'll just set a width of 200pts.
Step 3: Set the constraints between textView and its parent, redView. Let's say we want a 10pt border all the way around. Let's add these constraints:
Once we've added these constraints we'll gets some auto layout warnings and errors. For starters, because the constraints I added for with and space to superview don't match the actual sizes, I'll get some warnings like this:
There will also be some errors describing missing X and Y positions for redView and for textView. There are really twice as many errors here as necessary. textView knows where to position itself relative to redView. We don't need more constraints to sort out textView's position. However, redView doesn't know where to position itself yet... and so ultimately, textView also sort of doesn't exactly know.
We can update the textView's frame to get rid of the warnings, but let's go ahead and fix the actual errors.
Step 5: Set up redView's constraints relative to the superView. redView already know what size to be. Notice we had no errors for redView's width. It just doesn't know where to be. In this case, I'll go simple and say we want redView to be centered. So we'll want to add these constraints:
Now we've fixed some of the problems. The only problem that remains is the height for everything.
To fix this, we must set the content sizing priorities of textView. Set these all to 1000 and change the "Intrinsic Size" property to "Placeholder".
By now, all of the auto layout errors should be gone and we should only be left with warnings because our storyboard frames don't match what our constraints say they should.
We can fix that by selecting parentView and updating all the frames:
There's one final caveat to this auto layout puzzle when it comes to autosizing based on content size: what happens if our text view has no content?
If our textview has no content, auto layout will choose a height of 0, and our users won't even be able to see that there's a text view there, much less tap in it to add content (and make it expand). When using auto layout and content-based sizing, we should almost always be sure that we've set either an explicit or minimum size for the content view.
We don't have to worry about our textView's width, as we set this explicitly to 200. So let's add a minimum height constraint. Start by adding any height constraint:
Now go to the size inspector for the textView, find this height constraint we added, and edit it into a greater than or equal to constraint:
Storyboard won't reflect the change in content in our textView and resize it appropriately, but your constraints are now set up correctly and this will behave appropriately on your device or in the simulator.
ON UITextView make your you unselected These
Scrolling Enabled
Bounces
Bounce Horizontally
Bounce Vertically
Shows Horizontal Indicator
Shows vertical indicator
Now Change your auto layout constraints like this.
On the Storyboard Page, click on your textview.
Then click on the small triangular in the lower right corner.
Click first on "Clear Constraints".
An then on "Add Missing Constraints".
Its the easiest way.

Resources