[go: up one dir, main page]

0% found this document useful (0 votes)
292 views62 pages

Adaptive Auto Layout - SViOS Slides

The document discusses adaptive auto layout and responsive design in iOS. It covers key concepts like size classes, trait collections, and handling rotation and resizing of views. The speaker emphasizes that layout decisions should be based on a view's size class rather than size, orientation or ancestors' traits. Interface Builder tools for auto layout and managing constraints across size classes are also demonstrated.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
292 views62 pages

Adaptive Auto Layout - SViOS Slides

The document discusses adaptive auto layout and responsive design in iOS. It covers key concepts like size classes, trait collections, and handling rotation and resizing of views. The speaker emphasizes that layout decisions should be based on a view's size class rather than size, orientation or ancestors' traits. Interface Builder tools for auto layout and managing constraints across size classes are also demonstrated.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 62

Adaptive


Auto Layout
Silicon Valley iOS Developers' Meetup
March 2015

Tyler Fox
@smileyborg
Layout
What is Layout?
y
x

View height

width

#SViOS Adaptive Auto Layout @smileyborg


Manual Layout

view.frame = CGRect(x: x,
y: y,
width: width,
height: height)

#SViOS Adaptive Auto Layout @smileyborg


Auto Layout

view.frame

an output calculated by the auto layout engine


based on your constraints

#SViOS Adaptive Auto Layout @smileyborg


Living in an
Adaptive World
http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions
#SViOS Adaptive Auto Layout @smileyborg
Size Classes

enum UIUserInterfaceSizeClass : Int {


case Unspecified
case Compact
case Regular
}

#SViOS Adaptive Auto Layout @smileyborg


Size Classes
enum UIUserInterfaceSizeClass : Int {
case Unspecified
case Compact
case Regular
}

Regular
Regular

iPad iPad
Regular Regular
Portrait Landscape

#SViOS Adaptive Auto Layout @smileyborg


Size Classes
enum UIUserInterfaceSizeClass : Int {
case Unspecified
case Compact
case Regular
}

Compact
Compact

iPhone iPhone
Regular Compact
Portrait Landscape

#SViOS Adaptive Auto Layout @smileyborg


Size Classes
enum UIUserInterfaceSizeClass : Int {
case Unspecified
case Compact
case Regular
}

Compact
Regular
iPhone iPhone
Regular 6 Plus Compact 6 Plus
Portrait Landscape

#SViOS Adaptive Auto Layout @smileyborg


Traits

UITraitCollection

horizontalSizeClass Compact

verticalSizeClass Regular

#SViOS Adaptive Auto Layout @smileyborg


Traits
<UITraitEnvironment>
UITraitCollection

UIScreen horizontalSizeClass Compact


UIWindow
UIViewController
UIView
verticalSizeClass Regular

* UIPresentationController also conforms to UITraitEnvironment


#SViOS Adaptive Auto Layout @smileyborg
Trait Environments
UIScreen

UIWindow
ChildVC1 UIWindow
UIScreen
ParentVC ChildVC2
ParentView
ChildView1 ChildView2

UIViewController

UIView

#SViOS Adaptive Auto Layout @smileyborg


UIScreen
UIScreen

UIWindow
UIWindow

ParentVC

UIViewController

ChildVC1 ChildVC2

ParentView

UIView
ChildView1 ChildView2

#SViOS Adaptive Auto Layout @smileyborg


Responding to Changes
UITraitEnvironment Screens, Windows, View Controllers, Views

var traitCollection: UITraitCollection { get }

func traitCollectionDidChange(previousTraitCollection: UITraitCollection?)

UIContentContainer View Controllers

func willTransitionToTraitCollection(newCollection: UITraitCollection,


withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

func viewWillTransitionToSize(size: CGSize,


withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

* UIPresentationController conforms to both


#SViOS Adaptive Auto Layout @smileyborg
Rotation
iPad
768 Regular

1024 Portrait Regular

Change in size Same size classes

768 Landscape Regular

1024 Regular

#SViOS Adaptive Auto Layout @smileyborg


Rotation
iPhone 6 Plus
414 Compact

736 Portrait Regular

Change in size Change in size classes

414 Landscape Compact

736 Regular

#SViOS Adaptive Auto Layout @smileyborg


Handling Rotation

Dep
-[willRotateToInterfaceOrientation:duration:]

reca
-[didRotateFromInterfaceOrientation:]

self.interfaceOrientation

ted
-[willAnimateRotationToInterfaceOrientation:duration:]

#SViOS Adaptive Auto Layout @smileyborg


Handling Rotation in iOS 8
override func viewWillTransitionToSize(size: CGSize,
withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

// Code here will execute before the rotation begins.


// Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:]

coordinator.animateAlongsideTransition({ (context) -> Void in

// Place code here to perform animations during the rotation.


// You can pass nil for this closure if not necessary.

},
completion: { (context) -> Void in

// Code here will execute after the rotation has finished.


// Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:]

})
}

#SViOS Adaptive Auto Layout @smileyborg


Migrating Legacy Code
typedef NS_ENUM(NSInteger, ViewOrientation) {
ViewOrientationPortrait,
ViewOrientationLandscape
};

@interface UIView (Orientation)

/** Returns the "orientation" of size.


width > height is considered "landscape", otherwise "portrait" */
+ (ViewOrientation)viewOrientationForSize:(CGSize)size;

/** Returns the "orientation" of this view based on its size.


width > height is considered "landscape", otherwise "portrait" */
- (ViewOrientation)viewOrientation;

/** Returns YES if this view's height >= width */


- (BOOL)isViewOrientationPortrait;
/** Returns YES if this view's width > height */
- (BOOL)isViewOrientationLandscape;

@end

GitHub Gist
bit.ly/1BHOYoF

#SViOS Adaptive Auto Layout @smileyborg


Making Layout Decisions
✅ What are my size classes?

✅ What is my size?

🚫 What is the status bar orientation?

🚫 What is the device or screen size?

🚫 What traits or sizes do my ancestors have?

#SViOS Adaptive Auto Layout @smileyborg


Interface Builder
Auto Layout
Size Class Controls

#SViOS Adaptive Auto Layout @smileyborg


Size Class Controls

#SViOS Adaptive Auto Layout @smileyborg


Size Class Controls

#SViOS Adaptive Auto Layout @smileyborg


Placeholder Constraints

#SViOS Adaptive Auto Layout @smileyborg


Uninstalled Placeholder
Constraint Constraint
Uses • Customize constraint for • Silence compile-time IB
specific size classes layout warnings
• Allow easy runtime • Prevent IB from injecting
switching between constraints to fix ambiguous
constraints layout

Lifespan • Exists at runtime (but • Exists only in IB, never


inactive) created at runtime

IBOutlets • Can reference via outlets • No, runtime crash

Layout • Does not affect IB layout • Factors into IB layout


Checking checking checking

#SViOS Adaptive Auto Layout @smileyborg


Coding
Auto Layout
NSLayoutConstraint
view1.setTranslatesAutoresizingMaskIntoConstraints(false);
view2.setTranslatesAutoresizingMaskIntoConstraints(false);
let c = NSLayoutConstraint(item: view1,
attribute: .Left,
relatedBy: .GreaterThanOrEqual,
toItem: view2,
attribute: .Right,
multiplier: 1.0,
constant: 10.0)
c.priority = 750
c.active = true

#SViOS Adaptive Auto Layout @smileyborg


VFL
view1.setTranslatesAutoresizingMaskIntoConstraints(false);
view2.setTranslatesAutoresizingMaskIntoConstraints(false);
let views = ["view1": view1,
"view2": view2]
let metrics = ["spacing": 10.0,
"priority": 750]
let c = NSLayoutConstraint.constraintsWithVisualFormat(
"H:[view2]-(>=spacing@priority)-[view1]",
options: NSLayoutFormatOptions(0),
metrics: metrics,
views: views)
NSLayoutConstraint.activateConstraints(c)

#SViOS Adaptive Auto Layout @smileyborg


PureLayout

UIView.autoSetPriority(750) {
view1.autoPinEdge(.Left,
toEdge: .Right,
ofView: view2,
withOffset: 10.0,
relation: .GreaterThanOrEqual)
}

#SViOS Adaptive Auto Layout @smileyborg


PureLayout

The missing API


for Auto Layout

github.com/smileyborg/PureLayout

#SViOS Adaptive Auto Layout @smileyborg


PureLayout
• Complete API for Auto Layout
• Designed to be consistent with Apple's API style
• Balances simplicity and power
• Engineered to minimize third-party code
• Supports mixing and matching with other approaches
• Fully compatible with Swift & Objective-C
• Supports both iOS (6.0+) and OS X (10.7+)

#SViOS Adaptive Auto Layout @smileyborg


Adaptive
Layout Code
Idempotent

Produces the same results


when executed once or many times

#SViOS Adaptive Auto Layout @smileyborg


Idempotent
Produces the same results
when executed once or many times


func abs(x: Int) -> Int {
return (x < 0) ? -x : x
}

#SViOS Adaptive Auto Layout @smileyborg


Idempotent
Produces the same results
when executed once or many times

🚫
func purchaseItem(item: Item) {
charge(creditCard, forAmount: item.price)
}

#SViOS Adaptive Auto Layout @smileyborg


Idempotent
Produces the same results
when executed once or many times


func emptyCart() {
shoppingCart.removeAllItems()
}

#SViOS Adaptive Auto Layout @smileyborg


Idempotent Layout
enum Layout {
case A
case B
}

func layoutForCurrentState() -> Layout {


switch (traitCollection.horizontalSizeClass) {
case .Compact:
return .A
case .Regular:
fallthrough
default:
return .B
}
}

#SViOS Adaptive Auto Layout @smileyborg


Idempotent Layout
var layoutAConstraints: NSArray?
var layoutBConstraints: NSArray?

override func updateConstraints() {


switch (layoutForCurrentState()) {
case .A:
if (layoutAConstraints == nil) {
layoutBConstraints?.autoRemoveConstraints()
layoutBConstraints = nil
layoutAConstraints = setupConstraintsForLayoutA()
}
case .B:
if (layoutBConstraints == nil) {
layoutAConstraints?.autoRemoveConstraints()
layoutAConstraints = nil
layoutBConstraints = setupConstraintsForLayoutB()
}
}
super.updateConstraints()
}

#SViOS Adaptive Auto Layout @smileyborg


Idempotent Layout
func setupConstraintsForLayoutB() -> NSArray {
let constraints: NSArray = UIView.autoCreateConstraintsWithoutInstalling() {
self.view1.autoPinEdgesToSuperviewMarginsExcludingEdge(.Bottom)
self.view2.autoPinEdge(.Top, toEdge: .Bottom, ofView: self.view1)
self.view2.autoPinEdgesToSuperviewMarginsExcludingEdge(.Top)
}
constraints.autoInstallConstraints()
return constraints
}

#SViOS Adaptive Auto Layout @smileyborg


Modifying Constraints

✅ Efficient
Changing the constant of installed constraints

⚠️ Less efficient
Removing existing constraints

and installing new constraints

#SViOS Adaptive Auto Layout @smileyborg


Other Performance
Considerations

Activating optional constraints



is more expensive than activating

Required-priority constraints

Activating multiple constraints at once



can be more efficient than one-by-one

#SViOS Adaptive Auto Layout @smileyborg


Managing the
Complexity
Composition

View hierarchy is a tree of subviews.


Manage your layout in a similar way.

Table and collection views inherently model this,


as they are composed of cells!

#SViOS Adaptive Auto Layout @smileyborg


#SViOS Adaptive Auto Layout @smileyborg
#SViOS Adaptive Auto Layout @smileyborg
#SViOS Adaptive Auto Layout @smileyborg
Debugging
Auto Layout
System Generated
Constraints

NSAutoresizingMaskLayoutConstraint
Constraints generated for views not using auto layout

NSIBPrototypingLayoutConstraint
Constraints generated by Interface Builder to fix layout ambiguity

#SViOS Adaptive Auto Layout @smileyborg


Constraint Identifiers
let constraint: NSLayoutConstraint = /* ... */
constraint.identifier = "A helpful description of my constraint"

view2.autoPinEdge(.Top,
toEdge: .Bottom,
ofView: view1).autoIdentify("view2.top = view1.bottom")

UIView.autoSetIdentifier("Pin to Superview Constraints") {


self.view1.autoPinEdgesToSuperviewMarginsExcludingEdge(.Bottom)
self.view2.autoPinEdgesToSuperviewMarginsExcludingEdge(.Top)
}

#SViOS Adaptive Auto Layout @smileyborg


Runtime View Inspector

#SViOS Adaptive Auto Layout @smileyborg


UIView.h Debugging
Warning: For debugging only!
Do not use these APIs in shipping code.

@interface UIView (UIConstraintBasedLayoutDebugging)

- (NSArray *)constraintsAffectingLayoutForAxis:(UILayoutConstraintAxis)axis;

- (BOOL)hasAmbiguousLayout;
- (void)exerciseAmbiguityInLayout;

@end

#SViOS Adaptive Auto Layout @smileyborg


Advanced
Auto Layout
Harnessing the Power

Constraints
Auto Layout View
Engine Frames

Use offscreen views and constraints to


calculate frames for onscreen views

#SViOS Adaptive Auto Layout @smileyborg


#SViOS Adaptive Auto Layout @smileyborg
Offscreen Layout

#SViOS Adaptive Auto Layout @smileyborg


Offscreen Layout

New
startFrame:
CGRect

#SViOS Adaptive Auto Layout @smileyborg


Offscreen Layout

startFrame:
CGRect

New
endFrame:
CGRect

#SViOS Adaptive Auto Layout @smileyborg


Offscreen Layout

Grab the code on GitHub


github.com/smileyborg/AdaptiveAutoLayout

#SViOS Adaptive Auto Layout @smileyborg


Tyler Fox

@smileyborg

linkedin.com/in/smileyborg

github.com/smileyborg

You might also like