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

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.

Related

How to correctly use aspect ratio in swift xcode storyboard?

I've been scratching my head about this all day. I am try to have the iphone 6s reflect what the iphone 12 is showing. I'm not good at autolayout but I'd just like an idea or a point in the right direction so I can make it look like its counterpart. All help is appreciated.
(P.S I'm using storyboard and have never tried to do it programmatically.)
All help is appreciated.
The general idea...
use a Vertical Stack View holding 3 "rows" of Horizontal Stack Views
each Horizontal stack view holds two "tile" UIViews
set Alignment: Fill, Distribution: Fill Equally and Spacing: 0 on all the stack views
give the first view (in this image, the red view) an Aspect Ratio constraint ... from your image, it looks like you want 3:2.5
embed the stack view in a "container" UIView - I called it GridView
constrain the stack view >= 12 on all 4 sides
also constrain the stack view = 12 on all 4 sides, but give those constraints Priority: High (750) ... this will cause auto-layout to "pull" the stack view to the edges, but allow it to be narrower if needed
then we also give the stack view Center Vertical and Horizontal constraints
constrain GridView to Zero Leading, Trailing and Bottom
That will give you 6 tiles that will maintain their aspect-ratios based on device size, and it will center the vertical stack view if needed:
The next step would be to embed a "rounded corner bordered" view in each "tile" view, constraining it at 8-pts on all 4 sides (less or more to get your desired "spacing"):
Here's the result on an iPhone 12 and iPhone 6s:
As you can see, there is less vertical space between the labels and the banner and grid views, and there is slightly more horizontal space on the sides of the stack view.
Here's a link to the Storyboard source and class files I used for this, so you can try it out and inspect the elements. I used just enough to demonstrate. You would probably want to make a custom "tile" view class that would contain the rounded corner bordered view and label:
https://gist.github.com/DonMag/8a0b2d85bbbb4262e43d73e745826ee5
It's all the game of constraints if you want to handle this using story board.
There are multiple ways to achieve this UI. Either you can use UICollectionView and use UICollectionViewCells to show 2 cells in each column to manage the data or you can use UIStackView to manage your UI easily.
If you want square shapes, then you must use UIScrollView as the UI can exceed Screen Height. If not, just put your view in UIStackView and let it handle some of your UI constraints itself.

How to arrange UIStackViews?

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

Can't get Auto Layout and Stack Views to Auto-Adjust Properly (Swift 3, Xcode 8)

I'm new to iOS development so naturally I'm having some issues with my stack views and auto layout constraints in Xcode. Originally I had used just constraints and the pin menu to align everything but I'm really trying to get stack views down so I went back and implemented them.
If you look at my images above you'll see that in my app I created a couple of stack views:
Status Bar vertical stack
Section 1 vertical stack
1st divider (which is just a view with a height of 0.5 and is not inside of a stack)
Section 2 which contains 2 horizontal stacks inside of the main vertical stack view
2nd divider (exact same thing as 1st divider just between Sections 2 & 3)
Section 3 contains a vertical stack and horizontal stack inside of the main vertical stack
And all of these stacks plus the 2 dividers are grouped together in 1 super vertical stack called User Interface.
One of my problems is that I can't set top and bottom constraints between my stacks and dividers. As it stands, there is too much space for my liking between the sections and dividers. If you look at image 1 I tried to set a top constraint of 15 between Section 1 and Status bar. I also tried to set a top constraint of 15 between my 1st divider and Section 1, and so on and so forth. I'm getting conflicting constraints and I just can't figure out why. All they say is Section1.top = Status Bar.bottom + 15 , 1st Divider.top = Section1.bottom + 15, etc.
Any ideas on how to resolve the conflicts? Every time I try to move a divider it snaps back in its original place and adjusting the constraint numbers give me the same errors.
My second issue is that I can't get User Interface to fit inside of it's super view. I want my app to fit in all iPhone screen sizes and to auto adjust accordingly. What I tried doing is using the pin menu and pinning each side of my User Interface stack with a constraint of 0 (Constrain to margins unchecked). User Interface is aligned and without any conflicts but then all of my stacks get squished as seen in image 2. This results in a couple of errors saying that some of the heights and vertical positions of my labels are ambiguous:
Height and vertical position are ambiguous for "Bill Amount Text Field".
Height is ambiguous for "BILL AMOUNT".
Height and vertical position are ambiguous for "Tip Percent Segment Control".
As you go down the screen sizes there are more errors as more labels are being squished. And I already set individual top and bottom constraints for each label. Even when I implement a set height for each label, the error messages go away but not all of my labels appear within their stack. I tried messing around with the Alignment and Distribution menus and selecting different ones for my stacks but none of them seem to fix the issue.
Any help would be greatly appreciated or if I'm going about this all wrong please let me know. I'm using Xcode 8 beta 4 and wrote the app in Swift 3.0.
Refer to this documentation - there are pretty clear explanation of all auto-layout concepts.
I presume that your problem is that you use one big stack view, where each element fills proportionally to others. Try to fix this out.
One little advice, stacks are really good thing, but you should not abuse it :)
TL;DR;
From my experience. Stop using Interface Builder and create all views in code. With new anchor system or frameworks like SnapKit it's very easy. The benefits you get:
Faster development (after some time of practicing)
No stupid warnings from Interface Builder
Easier to merge when you work in a team
XCode almost never crashes
I was fighting with IB for few months and now I'm totally happy.
Good luck.

Xcode - Adding constraints to UITableView so that it fits all screen sizes

I've read quite a few tutorials and watched numerous videos on using constraints in Xcode. For some reason, I'm still missing certain aspects that are necessary to make the user interface look the way it's supposed to for all screen sizes.
Currently, I have a UITableView laying on a view controller. The view controller is set to "Inferred" size and I have all of the different sized devices open in Assistant Editor Preview to the right so I can view the changes. I've encountered multiple problems attempting to get the constraints correct for the different screen sizes.
Problem 1: The UITableView has a width set to 600. This causes dead space to the right of the table view on the iPad preview and it causes the UITableView to extend too far on the smaller devices. If I make the width of the table view smaller so that it fits within the preview of all screen sizes and then pin the left and right edges of the table view to the edge of the Superview by specifying 0 and unchecking constrain to margins, the result I'm seeing in preview is that the entire table view disappears completely from each device size. I was surprised by this because I thought by pinning the table view to the margins, it would make the table view fit within each of the screens.
Problem 2: (This is a completely different scenario from Problem 1, above.) In this situation, I've left the size of the table view to 600 and just specified constraints for the internal components of the cell contained within the tableview. In this case, the table view is still slightly not wide enough for the iPad dimensions and it extends too far on the smaller devices which makes components in the cells to be truncated and off of center.
I've primarily been working in Storyboard with Any width, Any height set. However, if I change the setting to Compact width, Any height, I can alter the constraints to fit the smaller devices a little better, but there's still a problem with getting things to work between the 5.5 inch screen and the smaller devices.
I would like to get my UITableView to extend all the way to the edges on each device and I would like to have the view inside of the cell remain centered and keep it's relative size on each of the devices. Does anyone have any suggestions on how I can accomplish this?
if you want to make your tableview to "fill" the whole screen (device-independent) the only thing you have to do is to pin its 4 edges (top, left, bottom, right) to its superview (the viewcontrollers view in your case) with a constant of 0.
you do not specify a specific width (like in your case 600) or height.
good luck :)

Not understanding auto layout, constraints and size classes

I'm a bit stuck and any help would be greatly appreciated!
I'll give you a quick overview. I have designs for a screen that were built in sketch using an iphone 6 screen size, then redesigned to fit and look right for an iphone 5/5s/5c, and 6 plus as those are the only devices that I want to support.
But the design portion or implementing the designs for just one specific screen size is easy and I understand that part. Where am I'm lost completely, is how to implement a design in one view controller that looks the way that it should in all the screen sizes I designed for.
I've gone through more than a few auto layout and size class tutorials and not sure how I properly use them so that the app recognizes "this is an iphone 5, use these image sizing and placements instead, and this is an iphone 6 plus, use these" and so on.
Everything I've seen to this point regarding auto layout and constraints only use 1 set of numbers to judge distance from elements for example, but all screen sizes would have different distances.
What am I missing or not understanding? I know I'm looking at something improperly.
Thanks in advance for all help!
You're correct that just one set of numbers could be used to judge distances, but this can still describe how a view should appear on different screen sizes. Your problem may be that you're thinking of constraints as describing the frame of your view? (Which obviously has to be different on every device). I find it more helpful to think of constraints as describing how each edge of my view relates to another view.
For example here's a view controller I setup with all the same constraints and how it would look on different devices. The constraints describe how the large grey view is pinned it's left and right edges 20 points from the left and right edges of its container view. It's pinned to 8 points from the top and 8 points from the top of the label. The label is centred vertically and horizontally and it has intrinsic content size. Each button is pinned 20 points from the bottom edge with button 1 and 2 being pinned to the 20 point from the left and right edges respectively.
I don't know if that helped or if that wasn't the answer you were after and you need to arrange your views differently depending on the device: you can tell Xcode which device size and orientation the constraints you're creating are for, using this button in Interface Builder.
Use it to select a device size/orientation. After, any constraints you create will only be used on that device. By default any width and height are selected so normally your constraints are applied to all devices.
Also, you cannot choose which devices you want to support, only the iOS version.

Resources