Use Different Spacing Values in UIStackView - uiview

Is there a way to use different values for the spacing between views within a UIStackView? As I understand it, the spacing property is used for all views (or rather the room between them). I was hoping to just set the top space constraint to some value for each view but this seems to be ignored. Any suggestion? Thanks!

It looks like there is no build in solution for this. So we went with spacer views. We just added plain UIViews with our desired heights as elements of the UIStackView. It's not beautiful but it does the trick.

Related

How can I make a custom grid inside a CollectionViewCell using autolayout?

I have a UICollectionViewCell in which I want to display some UIButtons with in some custom grid, like this:
As you can see I have different kind of arrangements for the grid, I actually have these possibles types of arrangements that depends on the data I have:
I'm trying to know how to accomplish this, I don't know what's the best way to have this different types of grid arrangements inside the cell. One first though was to make a different UICollectionCiewCell for each arrangement but since there's also other views inside the cell like the white rounded view, the title and the subtitle, I think that's not the best way to solve this. Then I though about using XIB files or maybe a ContainerView but I really don't know what's the best way to do this.
But the biggest problem here is also how to set the constraints for this type of view, I was trying with the constraints in storyboard but that didn't help a lot, maybe I should set the constraints programmatically or maybe even do a XIB file for each arrangement and each device haha.
This is what I had in my Storyboard that didn't work as I though:
All the buttons are inside a view with a constraint of aspect ratio, bottom, left and right constraint to 11 each one.
I have the buttons with aspect ratio constraint, the red views are just spacer views with width or height of 2 as a constraint, and all the buttons have top, left, right and bottom constraint to 0 with its closer view.
But as I said before this didn't work well.
Please comment or answer any idea or question you have.

How we can increase width of two button when we remove third button from view

I have view with three button with equal size. Each button take 1/3 part portion of view.
Like this image:
If I remove/hide one button then two button width should increase equally and take 1/2 portion of view. if I remove two button then one button size should be equal size of view.
My question is, how it's possible using the Autolayout.
Best option is using stackView. StackView gives lots of flexibility in adding or removing items. If you wish to use only auto layouts, you can achieve it by connect it's width constraints as IBOutlet and change the values programatically.
Best way to do that is to use UISTACKVIEW.Place a stackview and add 3 buttons.You can give proper layout constraints to the stack view as you need
click on stack view-- select attribute inspector
change distribution--fill equally
spacing--0
Then after that if you hide any button,other buttons will be automatically adjusted in width
Other Possible sol to this problem is Adding or removing constraints during runtime is a heavyweight operation that can affect performance. However, there is a simpler alternative.
For the view you wish to hide, set up a width constraint. Constrain the other views with a leading horizontal gap to that view.
To hide, update the .constant of the width constraint to 0.f. The other views will automatically move left to assume position. and for equal width pervoid multiplier to width..
You have a few options:
UIStackView which was made exactly for this.
UICollectionView similar to UIStackView in a certain way, but not really meant for this. However, it does the job nicely and it's easy to implement. Sometimes easier than UIStackView.
NSLayoutConstraint by using multiple constraints with different priority so that you can activate/deactivate them as needed and get the desired result. This approach is a bit more complex by it gives you the highest degree of control and flexibility over the views in your hierarchy.
The best way to achieve what you are looking for is, like others have already mentioned, to use a UIStackView.
When the isHidden property of a UIView inside a stack view is set to true, that stack view will hide the view and take care of the layout, so you will only need to set the correct constraints for your stack view.

Autolayout vertical spacing of group of textlabels when one is empty

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

Content hugging priority Dynamic Cell Size

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.

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