Slide 1

Slide 1 text

Dynamic Type @parrots

Slide 2

Slide 2 text

Dynamic Type @parrots

Slide 3

Slide 3 text

Dynamic Type @parrots

Slide 4

Slide 4 text

One of the many things you know you should do, but haven’t gotten to yet. • Dynamic Type • Localization • Voiceover

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

~30% of Slopes users use a non- standard font setting.

Slide 10

Slide 10 text

Auto Layout Everywhere Interface Builder First About Slopes

Slide 11

Slide 11 text

Easier than ever!

Slide 12

Slide 12 text

iOS 7: Classes of fonts (“Body”, “Header”, etc) iOS 9: More classes (“Callout”, “Title 1”, “Title 2”)

Slide 13

Slide 13 text

7 Sizes

Slide 14

Slide 14 text

iOS 10: adjustsFontForContentSizeCategory

Slide 15

Slide 15 text

iOS 11: 5 “Accessibility” Sizes

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

iOS 11: UIFontMetrics

Slide 19

Slide 19 text

OK, So, How-do?

Slide 20

Slide 20 text

Use a system font size (body / etc) Enable adjustsFontForContentSizeCategory Automagic

Slide 21

Slide 21 text

Doesn’t work with bold

Slide 22

Slide 22 text

let metrics = UIFontMetrics.init(forTextStyle: UIFont.TextStyle.callout) label.font = metrics.scaledFont(for: UIFont.systemFont(ofSize: 16.0)) label. adjustsFontForContentSizeCategory = true Automagic - Custom Font

Slide 23

Slide 23 text

viewDidLoad() { … let metrics = UIFontMetrics.init(forTextStyle: UIFont.TextStyle.callout) label.font = metrics.scaledFont(for: label.font) label. adjustsFontForContentSizeCategory = true Automagic - Custom Font in IB

Slide 24

Slide 24 text

Only do this once per label otherwise

Slide 25

Slide 25 text

UIApplication.shared.preferredContentSizeCategory traitCollection.preferredContentSizeCategory Not Just for Fonts

Slide 26

Slide 26 text

if UIApplication.shared.preferredContentSizeCategory >= .accessibilityMedium { return 2.5 } else if UIApplication.shared.preferredContentSizeCategory >= .extraLarge { return 1.2 } else if UIApplication.shared.preferredContentSizeCategory >= .extraExtraLarge { return 1.8 } return 1.0 Not Just for Fonts

Slide 27

Slide 27 text

let metrics = UIFontMetrics(forTextStyle: UIFont.TextStyle.footnote) let graphLineWidth: CGFloat = metrics.scaledValue(for: 1.0) Not Just for Fonts

Slide 28

Slide 28 text

Won’t automatically update

Slide 29

Slide 29 text

Change graph height Change stroke widths

Slide 30

Slide 30 text

Planning for Expansion

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Planning for…

Slide 34

Slide 34 text

Planning for Expansion

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory { //update whatever is needed } } Responding to Changes

Slide 38

Slide 38 text

UIContentSizeCategoryDidChangeNotification Responding to Changes

Slide 39

Slide 39 text

WWDC 2017 #245: Building Apps with Dynamic Type

Slide 40

Slide 40 text

Tip 1: Accessibility Inspector

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Tip 2: Something is better than nothing.

Slide 43

Slide 43 text

Don’t even have to do every size all at once.

Slide 44

Slide 44 text

80 70%

Slide 45

Slide 45 text

class SlopesApplication: UIApplication { @objc dynamic override var preferredContentSizeCategory: UIContentSizeCategory { get { if super.preferredContentSizeCategory >= .accessibilityMedium { return UIContentSizeCategory.extraExtraExtraLarge } return super.preferredContentSizeCategory } } } Limit Size via UIApplication

Slide 46

Slide 46 text

Don’t even have to do every screen all at once.

Slide 47

Slide 47 text

Tip 3: Use system components They just work!

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

Self-Sizing Cells:

Slide 50

Slide 50 text

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension }

Slide 51

Slide 51 text

Built-in Sizes

Slide 52

Slide 52 text

… most of the time

Slide 53

Slide 53 text

Tip 4: Know Thy Sizes

Slide 54

Slide 54 text

UIFontMetrics.init(forTextStyle: UIFont.TextStyle.body)

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

Grows Grows Shrinks Doesn’t Shrink

Slide 57

Slide 57 text

func autoSize() { let bodyFontMetrics = UIFontMetrics(forTextStyle: .body) for label in manualResizeBodyLabels ?? [] { label.font = bodyFontMetrics.scaledFont(for: label.font) label.adjustsFontForContentSizeCategory = true } let footnoteFontMetrics = UIFontMetrics(forTextStyle: .footnote) for label in manualResizeFootnoteLabels ?? [] { label.font = footnoteFontMetrics.scaledFont(for: label.font) label.adjustsFontForContentSizeCategory = true } …

Slide 58

Slide 58 text

Tip 5: Plan for Alternate Layouts AKA Stack Views, Stack Views everywhere

Slide 59

Slide 59 text

if UIApplication.shared.preferredContentSizeCategory >= .accessibilityMedium { stack.axis = .vertical stack.spacing = 8.0 } else { stack.axis = .horizontal stack.spacing = 24.0 }

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

Tip 6: Doesn’t have to be pretty, especially at accessibility sizes

Slide 64

Slide 64 text

Use maximums where they make sense .scaledFont(for: label.font, maximumPointSize: 40.0)

Slide 65

Slide 65 text

Tip 7: Pay Attention To Baselines Especially in UITableViews

Slide 66

Slide 66 text

My Text Their Text

Slide 67

Slide 67 text

My Text Their Text Top = Top + 8 Bottom = Bottom + 8

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

My Text Their Text My Text Their Text

Slide 70

Slide 70 text

My Text Their Text My Text Their Text Spacing relative to baseline

Slide 71

Slide 71 text

label.firstBaselineAnchor.constraintEqualToSystemSpacingBelow( contentView.to pAnchor, multiplier: 1.0) contentView.bottomAnchor.constraintEqualToSystemSpacingBelow( label.lastBa selineAnchor, multiplier: 1.0)

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

No specified height

Slide 74

Slide 74 text

No content

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

How’d it go?

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

2 weeks

Slide 79

Slide 79 text

Thank You @parrots