How to arrange UIStackViews? - ios

I'm starting a new project that supports iOS9 upwards and after looking at Apple's constraint guidelines they appear to suggest using StackViews whenever possible. After reading a few articles and the apple documentation I've a basic understanding of how to create them and their benefits but I'm still not sure when not to use them and how to arrange them.
For example in the below view should I use:
One big StackView on a vertical axis that covers the entire super view.
Three StackViews with regular constraints pinning them to each other and the super view.
One big StackView that covers the entire super view with three stack views within that view
No StackViews, this view isn't suitable
In general how do I decide how I layout my stackviews and whether to use them?

I've started to use stack views more and more, especially since Xcode 8.x. Every stack view you add saves you adding some auto layout constraints (3 vertically stacked labels in a view would probably need 9 constraints, that could be just 3 with a stack view)
If all elements are in vertical stack views, it's unlikely you'd need to embed one inside another - you'd usually do that when you have a horizontal one inside a vertical, or vice-versa. So in the example above, I'd start with one large stack view.
In Xcode 7.x there were issues with the intrinsic sizes of UILabels not being calculated correctly. In these cases, you can set a placeholder intrinsic size for each label in the size inspector.
That problem aside, get stacking!

I have a problem and can't see your screenshot but I have some points that help you decide:
Do use stack views for all linear arranged views
I prefer set the root stack view to the size that contains exactly the content without whitespace (so constraint it to be as the superview size only if that's the content size)
The stack view uses auto layout to determine the size of it's subviews, so you should validate that your subviews do tell their best suitable size - maybe by using intrinsicContentSize() [only when needed!] (be careful with it)
you can practice stack views in interface builder, try to change stack view properties, hide subviews (with hidden property), and play with constraints, it's great!
Good luck =]
Have a nice play

Related

Xcode - Vertical Stack of Horizontal Stacks constraints

I'm very new to using Interface Builder and Auto Layout so please bear with me.
I'm trying to lay out a vertical stack of horizontal stacks, with each horizontal stack being made up of a label and another horizontal stack of two labels. The whole vertical stack is wrapped in another view that has 10 points left and right constraints. I want the two stack elements of each horizontal stack to be at the edges of the stack.
I can get the layout to look how I want it on the interface builder but when I run it, the Sunrise AM/PM label gets cut off.
Storyboard next to simulator instance where AM label is truncated
View hierarchy with constraints
Please let me know if there's anything unclear about what my goal or my issue is.
The Problem is that your programm does need to truncate something to fit everything on the screen. Since you probably did not define which element to truncate (by altering the compression resistance) it takes the last one in the stack - the am/pm one. Changing the compression resistance should fix this.
Check out this guide to learn about it.

How to have Auto Layout set up a grid of icons proportionally for each device

I am coming across a few issues with Auto Layout when I set up my storyboard.
I want my app display to be identical (image size, spacing, proportions) on each generation of iPhone.
I have somewhat achieved the results that I want by setting each UIImageView to have central Autoresizing and an Aspect Fit Content Mode; however I cannot get the same results once I place the UIImageViews into Stack Views which I have been lead to believe is the proper way to set up this 4x4 icon grid.
Any help is greatly appreciated and if any clarification is needed please let me know.
Stack Views are here to simplify things.
You need 4 horizontal Stack Views inside 1 vertical Stack View.
Then, you need only 4 constraints in the vertical (main) Stack View: Left, Right, Bottom and Aspect Ratio (1:1).
The Stack View configurations are all the same: Fill and Fill Equally.
In my example I also added a space of 10 to each Stack View.
Like this:
Bonus: notice that I'm not using UIImageViews, but custom UIViews,
which draw themselves at runtime. You can even live-preview then in
Xcode via #IBDesignable and #IBInspectable.
Results
iPhone SE:
iPhone 6:
iPhone 7 Plus:
Take a look at the code:
git clone git#github.com:backslash-f/grid-on-stackview.git
(Please give Stack Views a chance. :-))
If the above gives you difficulty, which will not be the case, you can use a container view AutoLayout pinned to the 3 edges. Then place a https://developer.apple.com/reference/uikit/uicollectionview in the container view and set up the collection view with your data source. This is how I solved this problem in the past. Be sure to shut off the scroll, bounce, and control the amount of data source items to perfectly fit the numbers of the grid.

IOS: Embedding views in stack creating a stack with > 10,000 pts size

I am trying to embed 4 UILabels and a UIView into a stack view. I selected all the labels then click the 'embed in stack' option. This then causes the labels to disappear from the view controller with ridiculous widths and X positions (e.g. one of the labels went from a width of 300 pts to 61,000,000 pts.) All the views I am trying to embed have correct constraints with each other and the rest of the view controller.
I've attached a photo of the views I am trying to embed in a stack (giving them background colours for visibility).
UI elements I want to embed in stack
All the views I am trying to embed have correct constraints with each other
There's your problem (at least in part). Do you understand what a stack view is? It is nothing but a shortcut for making constrains on its embedded views. It is a contraint maker.
For a stack view to work on your labels, therefore, your labels must have no constraints to one another. Rather it is the stack view itself that must be constrained (and the failure to do that sounds like the other half of your problem).
If u have a space when u want to put stackView, first put stackView, add constrains to that stackView and add the subviews on it.

Floating view into second row with autolayout

Can I setup constrains on storyboard view controller views so that I will have three views one next to other when there is enough horizontal space. In other case it will "float" one of views to next line?
Like on this example:
Enough space
Texts causing third view to "float"
Maybe stack views can help here?
There is no reason to expect the auto layout system to be able to accomplish this, nor can it.
What you want to use here is a collection view (UICollectionView) and have each of your views be a cell in the collection view. In fact, if you look at your views, they look quite the reusable views, where each one has an icon, a title and a detail text. A collection view can be set up to put cells one next to the other until there is no more space, after which cells are added below, and so on.
You can then setup your scene to layout around your collection view using auto layout, where other views would reposition correctly below the collection view content when the collection view grows in height.
See this layout as an example of what you need.
No. There is no way to setup views and constraints in a storyboard that automatically float into a new row if they don't fit into the same row.
(In my opinion that's a big weakness of the Autolayout system.)
The reason for that lies in the concept of constraints: Mathematically they represent linear equations that are normally independent for the x and y dimension. The only exception are aspect ratio constraints that connect the width of a view with the height of that (or another) view. But I cannot think of a way how you could use an aspect ratio constraint to break views into a new line if needed.
When the system resolves your constraints at run-time and computes the actual frames of your views it simply solves the system of linear equations for each dimension (or for both dimensions if an aspect ratio constraint is present). Adding the option of floating views to the Autolayout system would make the whole layout process a hell of a lot more complicated because you cannot describe that behavior as a simple linear equation.
(Stack views won't help as they only work for one dimension as well: either x or y.)
Recently, I needed the very same floating behavior you described and created a FloatingContainerView subclass of UIView. I generalized it so you can use it for any kind of view and translated it into Swift.
You can now find it on GitHub:
https://github.com/mischa-hildebrand/FloatingContainerView

How do I prepare a UIViewController's view for being added to a UIStackView?

This is what I'm trying to do...
I have one view controller that needs to dynamically display different subviews based on the presence of some data.
Here is a simple mockup. Each colored block represents a unique subview.
Sometimes the green block needs to be at the top, sometimes the green block won't display at all, sometimes the light blue block will be something different, etc.
Each subview has interactive elements, so I've been creating and adding them like so:
Defining a new view controller
Defining its view
Calling addChildViewController and didMoveToParentViewController
Calling addSubview on myNewViewController.view
Using SnapKit to make auto layout constraints to position the view
I want to transition to UIStackView because it seems a good support system for this view because all I need to do is stack its subviews. I'm seeing many conflicting constraint errors and unexpected view frames when trying to add subviews with their own inner auto layout constraints.
Question
Am I setting myself up for failure here by embedding the views of 4-6 view controllers in the view of one view controller?
Also, how do I give the added views properties like minimum heights or content sizes without seeing many breaking constraints with UIStackView? (So they can stack, but one of them is say, 400 tall, and the other is 200 tall)
Answer
You can absolutely do this using UIContainerViews combined with UIStackViews and UIScrollViews, it's a complicated setup so here's a starter project to get you started:
https://github.com/Rnorback/ScrollingStackView
Here's what that project looks like:
You want the containers to have different sizes. In order to do that, simply add height constraints to the containers with Autolayout. If you want to change the height of the scrolling. Then you'll need to change the height constraint of the UIStackView.
Brief Explanation
When creating this setup, you have to make sure the UIStackView distribution setting stays in fill. That way you can set height constraints on UIContainerViews.
When setting up anything in a UIScrollView you have to make sure that the object is pinned to the edges of the scroll view and has a defined width and height, otherwise the scrollview will throw a constriant error. I think of it like the scrollview tries to press in on all sides of your content view and if any side gives, the scrollview won't be able to present it properly.
Hope this helps.

Resources