Programing AutoLayout philosophically

The 22th day’s post of Mercari Advent Calendar 2019 is brought to you by @StingeSu from the Mercari iOS team.

I usually write articles on my Medium, check it out if you are interested!

medium.com

About AutoLayout

iOS AutoLayout which was introduced in 2012 and released in iOS 6. This AutoLayout system widely influenced iOS developers to create User Interfaces.

AutoLayout is an intuitive and describable layout system, it’s used to adapt to different sizes of devices. Compared with Flexbox in react, AutoLayout more focuses on the relations between every object. Using AutoLayout, every iOS screen is inspired by numbers of UIViews which contains numbers of NSLayoutConstraints.

f:id:stinge:20191221231237p:plain

Along with the evolution of AutoLayout, Interface Builder supports more and more flexible UILayout with UIStackView, Size Class, UIDeviceOrientation and so on. iOS engineers might even spend most of their time on creating the xib file, the remaining is for their architecture/model time. But a heavy xib file will have a performance issue.

For instance, the UIKit objects in the xib file would be loaded into memory while generating a UI screen by Interface Builder. Images(Cocoa Image cache), sounds(Cocoa Sound cache), and other local assets are all xml format plist documents. These plist documents need to be serialized into binary files in order to serialize xib file to a nib file. This will cost a lot of redundant(indirect) initialization through Interface Builder. Also, the NSLayoutConstraints need to be loaded after these heavy things.

f:id:stinge:20191221231352p:plain

Programatically

Using AutoLayout programmatically is always a hot topic on iOS-related articles. We may even easily create NSLayoutConstraint by functions or Layout Visual Format Language in the AutoLayout system. And thanks for the power of opensource, there are some awesome layout-related GitHub opensource projects, like SnapKit and PureLayout, to set constraints declaratively.

gist.github.com

gist.github.com

gist.github.com

These kinds of cool setting constraints method are almost created when viewDidLoad() or viewDidLayoutSubViews(), no matter what kind of layout system is used, some behaviors are different thinking ways compared with the AutoLayout system in the Interface Builder world.

Constraint Constant

Before setting AutoLayout constraints, don’t forget to disable autoresizing mask in views. 😉

In iOS, the UIKit objects are arranged from left to right, from top to bottom. In Frame’s concept, views are orientated to corresponding positions by Coordinate System (x, y, width, height). In AutoLayout, the relations between UIKit objects are defined all by NSLayoutConstraint.

Using Frame’s concept in the AutoLayout system might cause an ambiguous view after rendering ViewControllers. There might be some wrong while setting the parent view’s layout in the AutoLayout system but setting the child view’s layout in the parent view’s frame. What recommended is just to use one layout system in one ViewController(or even one app).

To adjust constraints’ constant in xib is very easy. The session 202, Introduction to Auto Layout for iOS and OS X@WWDC12, talked about setting constraints between one view(AView) and its cousin view(BView). The xib will add the constraint into two view’s parent view, neither AView nor BView. That makes developers can image the constraint world perfectly. All constraints of constraints are positive. But, the situation might be a little bit different in programmatically.

f:id:stinge:20191221231912p:plain

For instance, the NSLayoutConstraint about setting the margin between guide_mark image view and play button could be just set programmatically. Because the relative position is reversed in the iOS frame system, aware that the constant might become a negative number in the AutoLayout system.

gist.github.com

Ambiguous Layouts

Ambiguous layouts occur when the system of constraints has two or more valid solutions.

In some cases, the ambiguous layout won’t break your layout in the device but slow your app a few microseconds. While ambiguous layout happens in a child view, the parent view of it will have this ambiguous problem, too. One ambiguous layout might be fine, but lots of ambiguous layouts will make you harder to design the layouts. Also, the ambiguous layout might be only broken in the old iOS version. The best way is to design a no ambiguous layout UI.

Interface Builder is aware of this ambiguous layout problem, and try to give warning to developers. There are also some great GitHub opensource, like Interface Builder Linter and ambiguous layout detection.

This will become harder in setting NSLayoutConstraint programmatically. It still has some mechanism to avoid ambiguous layout, like setting a symbolic breakpoint for UIViewAlertForUnsatisfiableConstraints.

UIView-Encapsulated-Layout

UIView-Encapsulated-Layout-xxx(width/height) is not defined in Apple’s document. It will be activated automatically while the view is generated.

For instance, these constraints are activated in UINavigationController’s UINavigationBarContentView. the titleView is a UIView which in this UINavigationBarContentView. The NSLayoutConstraints in titleView might conflict with its parent view(UINavigationBarContentView).

f:id:stinge:20191221232622p:plain

The same situations will be included in TableView’s HeaderView/FooterView and TableViewCell, too. Any NSLayoutConstraint which conflicts with UIView-Encapsulated-Layout will become invalid. The titleView(customized view)’s autoresizing mask property will become false due to the AutoLayout setting. 

In order to make these inner NSLayoutConstraints become valid and render correct titleView in UINavigationController’s UINavigationBarContentView, we can use a wrapper which doesn’t disable autoresizing mask property to wrap the titleView/headerView/footerView.

gist.github.com

Programing AutoLayout is a kind of philosophy in the iOS development. There is no correct way to set UI layout. Considering the way for your iOS app will make your team have consistency. Be aware of some traps that slow or break your app.

Tomorrow’s blog – the 23th in the Advent Calendar will be written by AHA_oretama.

  • X
  • Facebook
  • linkedin
  • このエントリーをはてなブックマークに追加