UIKit: Apps for Every Size and Shape

Description: Ground-up coverage of how to make an app that can fit on devices of every size and shape. Make your app fit beautifully on Apple's full range of devices with the minimum amount of effort, future-proofing your user experience along the way.

Safe Area and Layout Margins

  • All non-iPhone X phones have a safe area that cover the whole screen, only iPhone X has a safe area that is smaller than the whole screen:
  • This is to take care of the on-screen home indicator and the notch (on landscape the safe area is symmetric). But Tvs can also have the same thing where the safe area is smaller than the whole screen
  • You can add your own Safe area insets (via a UIViewController):
  • Use .directionalLayoutMargins instead of .layoutMargins: the difference is in the declaration: the former uses .left/.right, while the latter uses .leading/.trailing: thanks to this difference, the latter adapts automatically to right to left (RTL) languages, while the former doesn’t

ScrollViews

Fundamentals

  • ScrollViews use contentOffset (.x and .y) as a way to represent the current scroll position of the scroll view
  • How to extend the scrollable area of a scroll view? .contentInsets to the rescue! These are insets we can define ourselves that will go from the edges of the scrollable area to the content inset
With contentInset.top = 20 the scrollable area is 20 points more, note how the contentOffset is not affected by the inset.we can scroll until the offset is -20
  • From iOS 11 every UIScrollViewController has a new (read only) property called .adjustedContentInset: contentInset is what we define, system inset is safe area and more, eg:

Building Adaptive Apps (put all together)

Let’s see an example:

This screen has a (1) content view (vertical scroll), embedded in a (2) navigation view, embedded in a (3) tab bar:

  • The tab bar sees only the safe area insets of the screen (home indicator + status bar):
  • The navigation controller is inside the tab bar, therefore it sees a smaller safe area that includes also the tab bar:
  • Finally the content view controller has an even smaller area because of the navigation view:

The idea of safe areas is encapsulation: one view shouldn’t know, nor care if it’s running on a iPhone X or else.

If you want to hide the status bar: you shouldn't because it doesn’t work on iPhone X.

What you can do is remove both the status and navigation bars at the same time: this way the experience will be more immersive.

Rendering text on a wide environment

iOS provides a readable width that we are recommended to use all the time, this width is based on the user selected dynamic type (and probably other accessibility options in the future):

extension UIView {
  var readableContentGuide: UILayoutGuide { get }
}

This guide works in also in narrow environments like the split screen above.

To adopt this in UITableView(s) there’s a property to set to true:

⚠️ the default value is false in iOS 12, but true in earlier iOS (iOS 11...) ⚠️

This parameter can be changed from the storyboard as well:

Apple suggests to leave the default value unless you know that you will display a lot of text in the table.

By default UITableViewCell .background and .selectedBackground will extend beyond the safe area, its content won’t:

If you want the content to also extend beyond the safe area, here’s how:

Missing anything? Corrections? Contributions are welcome 😃

Related

Written by

Federico Zanetello

Federico Zanetello

Software engineer with a strong passion for well-written code, thought-out composable architectures, automation, tests, and more.