Adaptive Design in iOS
Adaptive design exists to create UI which can adapt itself to the needs of user, device , content or context. Devices running your app can have different screen sizes and ratios, user may need larger fonts, length of string can vary for different languages. iOS have a number of techniques to develop adaptive design easily.
Auto Layout is a way that lets developers create user interface by defining relationships between elements. It provides a flexible and powerful system that describes how views and the UI controls relate to each other. AutoLayout allows to develop UI totally agnostic of what context it is placed into: tiny iPhone4S screen, long iPhone 5S, huge iPhone 7+, future wide screen of iPhone 8 or squeezed manually iPad window in multitasking mode.
Without using AutoLayout, the UI controls have fixed position: the “Press Me” button’s frame origin is set to
With AutoLayout we define relationships between elements: the “Press Me” button is centered horizontally in it’s container view and is placed
8pt lower than "Title" label.
- Auto Layout Concepts in iOS — Brad Bambara
- Introduction to Auto Layout in iOS Programming
- Auto Layout Magic: Content Sizing Priorities — KrakenDev
AutoLayout constraints can be set in InterfaceBuilder (in storyboards and nibs/xibs) or directly in code (directly creating
NSLayoutAnchors or via Visual Format Language)
Precise position of UI elements is defined according to constraints in runtime by autolayout engine. Debugging can be a difficult task, but thanks to Objective-C origins of UIKit we can add breakpoints to calls of autolayout engine’s methods. You can also audit constraints in Xcode’s Debug View Hierarchy tool.
Sometimes you want UI elements to be laid out differently for different screen sizes or different screen orientations. For example, Safari lays out currently opened webpages vertically for portrait orientation:
but for landscape orientation they are laid out in a 3-in-a-row grid: this allows to make more content visible and is more comfortable to use with two hands
SizeClasses are technique to make such setup easier. There are two size classes (height and width) with three values (compact, regular, any) describing approximate size of interface. Here is short chart of size classes:
InterfaceBuilder allows to customize constraints, colors, font sizes, images and many other things according to size classes. In code that can be done with
UIStackView is a container view that internally handles layout of its subviews. The layout can be configured by changing its properties axis (vertical or horizontal), distribution, alignment, and spacing. In runtime it is resolved with a number of ordinary constraints, and saves hours of developer's work by reducing the number of constraints you needed to create yourself for many common layouts.
- UIStackView Demystified - RaizException - Raizlabs Developer
- BlogRaizException – Raizlabs Developer Blog
UIStackView can dynamically add and hide it's subviews, animated.
In iOS 11 you can create stack views with custom spacing between views.
UILayoutGuides can be included into layout instead of invisible
UIViews that you can want to use in such situation:
They can be added in code only, but do not participate in view hierarchy and rendering of interface will be way faster.
DynamicType is part of iOS Accessibility toolkit: user can choose preferable level of font size (make it huge, for example, if she suffers from low vision) in iOS Settings, and all apps supporting DynamicType will automatically increase fonts size. Altho not so famous among developers, this feature is significant for great amount of users.
In order to support DynamicType, you have to choose one of system-provided text styles (headline, subhead, body, footnote, etc) instead of hardcoding font with predefined size. No other work is needed, but while designing UI pay attention that text can need more or less space (which is also important for multi language localization).
In iOS11 DynamicType received big update: supports custom fonts, automatically increase size of icons and images (thanks to support of vector assets),
UITabBar items can show their titles in over-the-interface-toast, etc.
Best Practices — for Product Managers and Designers
- Make your design independent of screen size; customize it depending on size class and screen orientation instead. Rearrange elements for tiny screens as well as for huge ones. Don’t think in terms of elements’ precise locations — think in terms of relations between them.
- Working on UI, pay attention that text can need more or less space — either because of localization, sudden changes or DynamicType. According to IBM research, average additional space needed for comfortable localization to most European languages is:
- Incorporate DynamicType! It is significant for users with low vision problem, of any age and any social group. It is cheap to implement and is almost completely automatic.
Best Practices — for Developers
- Use AutoLayout in InterfaceBuilder or in code, don’t hardcode frames of elements.
- Default to
UIStackView, it will dramatically decrease number of constraints you have to set up and maintain manually
- Be careful with constant distances. Don’t set hard height and width for elements with text — it will cause problems if text size will increase.
UILabelcan have multiline text, set
numberOfLines = 0— that will allow label to grow as long as it's text needs. If it is unacceptable, set
lineBreakMode = .byWordWrapping— that will continue decreasing font size until text length will suit label's frame or reach minimal value. By default, label have 1 line and text is truncated.
Algorithm of setting up size-class-dependent constraints in Interface Builder
- Build Base Layout. This is the “let’s get everything that we want on the screen” step, or the layout that we want to happen most of the time.
- Choose Size Class Override
- Uninstall Irrelevant Constraints. We’re talking Auto Layout here. You’ve got these constraints which determine the size and position of different views, and you can do this thing called uninstalling them. We’ve chosen a particular size class, and I want to take these constraints and throw them away.
- Add New Constraints Specific to Size Class. This is to make sure that we get the layout we actually want in this new size class.
- Rinse and Repeat. The important thing is to not go into your storyboard and build an iPhone portrait layout, then an iPhone landscape layout, then throw everything away before you move to iPad, etc. That doesn’t really help you at all. The approach is to start with a base layout, then work on top of it.
Written in July 2017, with respect to iOS10, some iOS11 and Xcode8.