Recently I've had a complex auto layout situation that has been solved (thanks to #Catalina T.). Currently I'm experiencing an issue with Content Hugging Priority. I have 4 dynamic labels that may contain huge texts so cells should fit the content. With the current constraints and priorities if I set huge texts to all dynamic labels it works perfectly (though one of them won't be displayed fully instead it will be clipped with dots). If I set the third label's text to a huge one auto layout goes crazy... I get something like this:
Whereas I want all the labels to be arranged consequently.
Demo project.
How to fix this issue?
Thank you in advance!
I managed to solve this issue.
AutoLayout should know leading, trailing, top and bottom constraints from all your dynamic views. Besides that it might happen that one view is huge and others are not, as a result you'll get the wrong arrangement. To solve this simply add Vertical Spacing for each dynamic views that are not yet connected with this constraint. Then you should change the constraint Relation to Greater Than Or Equal, so you'll simply notify the AutoLayout that you want these views to be arranged consequently.
Solved demo project.
Related
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.
I’m building an iOS app which includes a quiz. Questions are displayed in the upper portion of the screen (see below). There are always five possible answers. The thing is: the answers are procedurally generated and vary in length, which leads to line breaks in the label sometimes.
This is the current state
Maybe it’s hard to tell from the picture, but the spacing between the first and second and then between the second and third is not the same as I intend it to be.
This is what I had in mind
Essentially, I’d like the top- and bottommost labels to have the same space towards the container. The labels in the middle should all have the same spacing between each other, but should also adapt, if one of the labels gets bigger (when the size of a text is longer than the width and a line break occurs).
To achieve this, I tried the following:
Organise the labels as a stack view:
Nearly worked, the only problem I have here is, that the size of the
labels is calculated after the stack view is displayed, which leads to wrong constraints/paddings/margins being applied to the (possibly) longer texts at runtime.
Organise the labels with regular constraints
I tried setting the
priority of the constraints for the middle labels lower than
that of the top- and bottommost ones, so those would be the ones
to resize, if the labels enlarges, but it appears that at
runtime one of those is chosen to shrink, whereas the others
remain at their default size.
I'd really appreciate if you could help me out, constraints always seem to be a pain in my neck...
Agreed... I think UIStackView works fine, just have to set it up properly.
Also you may need to call .sizeToFit on the labels when you set the text.
I put up an example for you - the sizing is not exact, but you should be able to follow the technique...
https://github.com/DonMag/StackViewFun
I think the best practice in your case would indeed be to use a UIStackView. Then you have multiple option in solving this problem:
You can set the distribution of the UIStackView to Fill Proportionally and set a Minimum Font Size or Minimum Font Scale to your UILabels.
You can also set the distribution of the UIStackView to Fill and then manually specify the height of your containers. The UILabels should still have some Minimum Font Size or Minimum Font Scale.
EDIT:
I just realized you want to keep all UILabels to have the same font sizes. Then a possible solution would be to embed the UIStackView into a UIScrollView and constraint the UIStackView's Leading, Trailing, Top and Bottom constraints to the ones of the ContentView of the UIScrollView. In this way the height of the UIScrollView will adapt in accordance of the needed height by the UIStackView.
Hope this will help you!
I have a somewhat complex layout that I want to make constraints for.
Top three all need to be equidistant from each other and equal widths and heights. Bottom three need to be equal width and heights, and also equidistant from each other.
How come Xcode doesn't have an equidistant margin option? I can't create a specific margin constraint because it wont look correct on smaller devices. Nothing I do seems to create acceptable constraints.
Thanks!
For top three you need to create 5 additional views, place them between this three views and set that they should have the same width. One of them should have some constant width(than all other will get this width as well). Than bind them all by connecting leading and trealing constraints between them. Next thing to do, is to set your views width and height. Margin that you need will be that five views that you placed before between them.
The same thing you can do with your other views, just adding some views to make them as a margins.
Is it what you was searching for? If not Pls describe your problem and I will try to solve it.
As #Dan said, UIStackView is your friend. Put the top three in a horizontal stack view and the bottom three in a vertical one. Your other alternatives are to fiddle with the Multiplier on individual constraints, i.e. 0.0 0.333, 0.667. That would require a lot of work. One other choice, if you're willing to wait to use this in Xcode 8, is that Apple has reinstated the old springs and struts style of pre-Autolayout in Xcode 8, and allows you to use that as an alternative, and/or mixed in with auto layout in Xcode 8. Try the UIStackview first, though, it's the path of least resistance.
I have a cell that contains a container with 10 subviews (two of them are simply bounds and the others are labels). The scheme looks like this.
Dynamic labels may contain huge text so the cells should conform the appropriate size to fit the content. The question is how to set up all the constraints manually... I've tried a dozen of times to do it myself but seems I'm not that good at this. The table view supports auto dimension for row height and uses custom estimated height.
In Storyboard it looks this way.
Where blue views are a subviews of View C. A grey view behind is a View B. Bold labels are static and the others are dynamic.
Demo project.
How to setup constraints?
Thank you very much in advance!
I managed to setup your constraints so that you get the result you needed. This is what I get:
I hope this is how you wanted it to look like.
Here is a link with the project.
I will try to explain how I added the constraints so that it makes more sense.
First of all, you have view B which needs to be as big as the contentView. For this you add top/bottom/left/right constraints to the superView. Because you are using automatic dimensions, if you add all constraints with priority 1000(the maximum one), you will get some error with the constraints while running. This is because, before the cell size can be calculated automatically it is zero, so the constraints crash. Therefore, I set the priority for top and trailing space with a priority of 999 so that you don't see the error log anymore. The result is the same.
Then views C needs (top or bottom)/left/right and height constraint
Then you need to add the constraints for the labels. Since you need the right ones to have multiple lines, the constraints need to specify the vertical layout for this particular case. So, you have as follows: first label: top/left to name label and right to super view. All the other have top to the previous one,and bottom to the next one.
for the labels that don't need to resize you just need leading space to parent,horizontal space to the right label and static width. Also, you will need a constraint to align the top with the label on the right.
This is the result I get:
Hope my explanation made sense, just let me know if you have questions. Good luck with your project!
I really hate to ask here because I usually try to figure things out on my own. But on this one I've stuck for days and can't find a solution anywhere online.
I have a ScrollView containing multiple subviews. I've got an image view and two labels at the top with fixed heights. Then there is a UITextView and another ImageView (see pictures).
I add the text to the text view programmatically so it should have a dynamic height and the ImageView should move to the bottom so you can scroll. I don't want the TextView to be scrollable in itself but I want all the subviews to move as well.
I know I should be able to solve this issue using constraints. But I feel like I've tried everything and nothing worked yet. It worked when I disabled auto layout and moved the views manually. I'm wondering if there is a better way though.
As you can see I pinned the TextView to the ImageView above with a 1,000 priority and to the ImageView below with a 1,000 priority. The height constraint can not be deleted so I set it to the lowest possible priority. The ImageView on the bottom is pinned to the bottom of the superview with an absolute height. Its height constraint also has low priority. (I can post an image of the ImageView's constraints, if it helps)
I also tried adapting the frame programmatically but this is not working well in combination with auto layout. (If it helps I can of course post the code)
What am I doing wrong? Shall I just disable auto layout and do it manually? This seems unclean to me. Is it even possible to do?
I really appreciate your help :)
Greets,
Jan
Make sure the Scrolling Enabled attribute on the UITextView is unchecked in Interface Builder. I believe that the Auto Layout system takes that into account when it calculates the intrinsic content size.
If somebody is struggling with a similar problem: This is what I ended up doing:
Remove all subviews from the ScrollView in IB
Programmatically add a single UIView to the ScrollView.
Add all the views to the UIView as subviews (move them using setFrame)
Set the Frame of the UIView appropriately to the subviews
Set the ScrollView's contentSize to the size of the UIView.
A little more work but it finally works. This follows Apple's mixed approach guidelines that can be seen here (look for UIScrollView): http://developer.apple.com/library/ios/#releasenotes/General/RN-iOSSDK-6_0/index.html
The problem is the height setting. You somehow have to try to delete it. If you have added other constraints that are "sufficient", it should become deletable.
At the moment you have one user constraint for the height that is "Greater or equal" and an "Equals" constraint as well. Clearly, those are not working well together.
Maybe there is a conceptual error as well. The lower image view should not be fixed in position, so the distance to the lower image view will not be a "sufficient" constraint to let you delete the fixed height.
I think it should work if
the lower image view has a fixed height and
a fixed distance to the text view above, and
the text view has a minimum height as well as
a fixed distance to the image view above
(which should be fixed in relation to the superview).