Autolayout vertical spacing of group of textlabels when one is empty - ios

I have a group of text labels that are vertically spaced to each other 15 pixels.
The problem is that when one of the labels is empty, then there is extra space between the other two labels above and below the empty one (30 pixels).
I know that one solution would be to constraint all the text labels to the top and to the labels above and then I can just delete it and everything should look aligned but the problem is that I reuse the view and sometimes all the labels have text and sometimes some are empty. So if I delete the label, I would have to recreate it and readjust the constraints manually.
Is there a way to delete the extra vertical spacing when one of the labels is empty without deleting it?
Edit 1: The labels don't have any Height constraint so the empty one will be 0 pixels high
Edit 2: I need to support iOS7+

Possible options:
do not use multiple labels, but a single one, possibly using an attributed string if you need different formatting for the different parts
add an outlet to each of your constraints, and adjust the constant based on the label having text or not
There are quite a few others, including the use of table views, stack views (iOS 9+), and probably more...

If you are ok with supporting iOS 9 and above then you can use stack view and set the constraints for the labels within the stack view. But instead of emptying the label you should hide the label. When the label is hidden the stack view automatically brings up all the labels below it. You should get the desired behaviour using this method.

My rule of thumb is if layouts get overly complicated to do in Interface Builder, then it's better to just write code to do it. In this case I'm not even sure it's possible to define in IB. But even if it was, I'd do it in code. It's not a complicated layout, it will be more reusable, it will be cleaner in code.
A few options:
A - You could modify constraints in viewWillLayoutSubviews - it's kinda messy to hold on to so many top constraints. Somewhat less messy if you add them all to an outlet collection (array of outlets, basically).
B - You could manually adjust frames in viewDidLayoutSubviews - although it then begs the question, why even use AutoLayout at all if you're doing almost all the work manually anyway.
C - Use SnapKit and generate those constraints in viewDidLoad and / or update them whenever the text changes. I highly recommend SnapKit. Think of it as a sane way of programmatically creating AutoLayout constraints. It's very clean, and very simple.
See http://snapkit.io

Related

IOS/Storyboard/Autolayout. Center horizontal group of elements

Using autolayout in Storyboard, is there a straightforward way to center a group of elements without making them part of a subview?
For example if I have one label 50 and a second element Points, is there a way to hold them together as one and then center it.
Right now, I am able to hold the space between them constant (as it needs to be) and horizontally align but I can't get the two of them together centered. My approach has been to set a leading space before the first element and a trailing space after the second element, but something is throwing it off. I know I could combine them into one label and center it, but I'm looking for a solution that I can reuse every time I have one of these all too common situations.
Thanks for any suggestions.
Image:
Storyboard.
This scenario is very common and very simple to solve: just get rid of the leading and trailing constraints and instead add horizontalCenter to the first label regarding the view. After that all you gotta do is adding horizontalCenter to the second one regarding the first and you're set! Now both of them are linked together and well centered.
If you need more help with this, just share your repo and I'll fork it.
I know your question specified that you don't want to make the two labels part of a subview, but I'm not aware of a good way to do that and thought I would at least mention that the standard / recommended way to handle this situation would be to add "3K" and "Points" to a horizontal stack view, and then horizontally center the stack view and vertically constrain it to "Explorer" above.
This would ultimately require the same or less constraints as what you have now because you wouldn't need to create constraints for the labels inside the stack view.
See Apple references here:
https://developer.apple.com/videos/play/wwdc2015/218/?time=134
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/LayoutUsingStackViews.html

Having trouble with AutoLayout Xcode constraints

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.

Layout changing when running the app

I've been trying for days to make one layout of my app to work well, and after days of learning and mistakes I still can't get the table cell layout to look how I want it to be.
This is how my cell .xib looks like in the editor:
http://i.stack.imgur.com/VEr3r.png
And this is how my app looks like when running with suggested constraints:
http://i.stack.imgur.com/wiK1f.png
Why is that? How I can find my mistake and make the layout like it supposed to be, in the view?
Suggested constraints are rarely what I actually wanted to see.
For each label with fixed text, lock the horizontal and vertical positions either to the view or to the next adjacent item.
For imageViews, choose the size you want and lock the height and width.
For labels that you will be dynamically changing the text on, pick a size that will hold the longest string and lock the width. You'll need a vertical position constraint.
You have many options to simplify your layout.
you can use the stakview or create a static UITableView and insert your component inside the cells and enter the Constraint. excellent tutorial http://www.runtimecrash.com/2015/09/17/exploring-uistackview/

Complex AutoLayout for Cell with dynamic size

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!

How to make a fluid layout in iOS?

What is the proper way to make a fluid layout in iOS, in the sense that hidden elements do not take up space anymore?
I have a table view with in each cell a customized detail-type of view with title, subtitle and a row with some extra information:
The extra information can be up to three pairs of an icon and a label with a value. The layout of all views inside the cell is done using AutoLayout with no missing or ambiguous constraints.
What I would like to achieve is that when the value is 0, the icon and the label are not displayed and the views on the right are shifted to the left.
If I just use the setHidden: method, the width of the hidden parts are not changed, so that there is just whitespace, but no views are moved. Example:
It should look like this:
The following questions are related but do not seem to fit my case:
Fluid UI layout on iPhone
AutoLayout with hidden UIViews?
I have tried to follow the approach with creating layout constraints for the four frames that need to be set to zero: the width of the heart-shaped icon, the width of the label containing the value, the whitespace in between those and the whitespace between the label and the next icon. This did not work because I could not bind the layout constraints to the outlet in the code, and besides it seems a cumbersome method for something that should be a common scenario.
EDIT: I fixed the problem with the outlets to constraints: to do this it is necessary to create a subclass for the table cell and creating outlets for the constraints there.
With "common scenario" I refer to doing something similar in web design, where setting the display style to none is simple and has the desired effect. I expect that there is something similarly simple for this in iOS.
I have been thinking of using a collection view with reusable cells, but then I need to set up a delegate and a datasource and everything, and before I would go this way I wanted to make sure that that is the way to do it.
There is no need to remove a hidden view. Connect the constraint to an outlet in the code, and when you determine a view is hidden, subtract from the constraint's constant. Then, in the cell's prepareForReuse, remember to return the constraint's constant to the correct value.
Hidden views maintain their frame, so auto layout will have no reason to adjust the view. The correct way to do this would be to remove the views from the superview. The last thing you must do is double check the constraints. Since you will be removing views, you cannot use those views for auto layout. This will require quite a bit of constraint setting on your UI.

Resources