My typical solution for non-repeating view controllers nowadays is by using vertical UIStackView that is embedded within UIScrollView.
So the stack goes:
Main UIView -> UIScrollView -> UIStackView -> Views array
This stack is very easy to set up in storyboard or code and constrained with auto layout.
Naturally, the four sides of the scroll view will be constrained to the main UIView. The easiest way would be to use the tie-fighter icon. Notice that the top and bottom is glued to the layout guide instead of superview by default.
The problem arises when we embed this view controller inside a navigation controller, thus creating a navigation item bar. This action will then push the stack view (inside the scroll view) down 64 pixels, seemingly without reason.
If you constraint the scroll view to the top layout guide, the child stack view will be pushed down 64 pixels. That is 20 pixels for status bar and 44 pixels for navigation item. So you would need to change the constant to –64 pixels to stick the stack view to the top of the view. It is a fix but seems more of a hack than a real fix.
Why is this happening?
This is caused by constraining the scroll view to the top layout guide instead of the superview. But there is no obvious way to constraint the top of the scroll view to the top of main UIView.
￼ The common effort of using ctrl+drag will only offer you to constraint the scroll view to the top layout guide. Using the tie-fighter icon will do the same as well.
After you set up the constraint to the top layout guide and tried to edit it, there’s no way to change it to the superview either.
So how the heck do we constraint the scroll view to the superview?
It is not obvious. After some searching, I found out that we can click the little arrow button (dropdown?) when setting constraint constant from the tie-fighter icon. From there you can select if you want to constraint the view to the superview or the top layout guide.
Voila, problem solved.
What should have happened
Given the hidden nature of the feature, maybe Xcode could have done better to inform us about this option.
When ctrl+dragging, a small tooltip should show up to a ask us if we want to constraint either to the top/bottom layout guide or the superview. This wouldn’t be a big problem because it should only be shown to a view that is directly under the main UIView. The other nested views should work normally.
When editing an existing constraint, there should be an option to change from top layout guide to superview and vice versa. Currently, the only way is to delete the constraint and recreate them.
Xcode could have done better.