Slide 1

Slide 1 text

Mastering TextKit try! Swift NYC 2016 Katsumi Kishikawa kk@realm.io

Slide 2

Slide 2 text

Katsumi Kishikawa Realm Inc. kk@realm.io

Slide 3

Slide 3 text

kk@realm.io

Slide 4

Slide 4 text

kk@realm.io

Slide 5

Slide 5 text

kk@realm.io

Slide 6

Slide 6 text

kk@realm.io

Slide 7

Slide 7 text

Agenda ˖ )PXUFYUTMBJEPVUJOJ04 ˖ #BTJDUZQPHSBQIZ ˖ #BTJDVTBHFPG5FYU,JU ˖ "EWBODFEFYBNQMFT kk@realm.io

Slide 8

Slide 8 text

Text Layout after iOS 7 kk@realm.io

Slide 9

Slide 9 text

What is TextKit? kk@realm.io

Slide 10

Slide 10 text

TextKit is ˖ .PEFSOUFYUSFOEFSJOHFOHJOF ˖ #VJMUPOUPQPG$PSF5FYU ˖ )JHIMZJOUFHSBUFEXJUI6*,JU kk@realm.io https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/CustomTextProcessing/CustomTextProcessing.html

Slide 11

Slide 11 text

UILabel kk@realm.io

Slide 12

Slide 12 text

kk@realm.io UILabel

Slide 13

Slide 13 text

Font Metrics kk@realm.io

Slide 14

Slide 14 text

kk@realm.io Font Metrics https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/FontHandling/FontHandling.html

Slide 15

Slide 15 text

kk@realm.io Font Metrics https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/FontHandling/FontHandling.html

Slide 16

Slide 16 text

kk@realm.io Font metrics Baseline X-Height Cap height Ascent Descent

Slide 17

Slide 17 text

How to know the display size kk@realm.io

Slide 18

Slide 18 text

let size = CGSize(width: label.bounds.width, height: CGFloat.max) let boundingRect = NSString(string: text).boundingRectWithSize(size, options: [], attributes: [NSFontAttributeName: font], context: nil) kk@realm.io Get Bounding Rect Single Line

Slide 19

Slide 19 text

let size = CGSize(width: label.bounds.width, height: CGFloat.max) let boundingRect = NSString(string: text).boundingRectWithSize(size, options: [.UsesLineFragmentOrigin], attributes: [NSFontAttributeName: font], context: nil) kk@realm.io Get Bounding Rect Multiple Lines

Slide 20

Slide 20 text

kk@realm.io Get Bounding Rect

Slide 21

Slide 21 text

UITextView kk@realm.io

Slide 22

Slide 22 text

kk@realm.io UITextView

Slide 23

Slide 23 text

kk@realm.io UITextView

Slide 24

Slide 24 text

kk@realm.io UITextView

Slide 25

Slide 25 text

kk@realm.io Default margins

Slide 26

Slide 26 text

kk@realm.io Default margins textView.textContainer.lineFragmentPadding textView.textContainerInset UIEdgeInsets(top: 8.0, left: 0.0, bottom: 8.0, right: 0.0) 5.0

Slide 27

Slide 27 text

kk@realm.io Leading

Slide 28

Slide 28 text

kk@realm.io CJK Font font.leading

Slide 29

Slide 29 text

kk@realm.io Custom Font (Not built-in) font.leading

Slide 30

Slide 30 text

Reset Default Margins kk@realm.io

Slide 31

Slide 31 text

let textView = UITextView(frame: view.bounds) ... textView.textContainerInset = UIEdgeInsetsZero textView.sizeToFit() kk@realm.io Remove textContainerInset

Slide 32

Slide 32 text

let textView = UITextView(frame: view.bounds) ... textView.textContainerInset = UIEdgeInsetsZero textView.sizeToFit() kk@realm.io Remove textContainerInset

Slide 33

Slide 33 text

kk@realm.io Remove textContainerInset

Slide 34

Slide 34 text

let textView = UITextView(frame: view.bounds) ... textView.textContainer.lineFragmentPadding = 0 textView.sizeToFit() kk@realm.io Remove lineFragmentPadding

Slide 35

Slide 35 text

let textView = UITextView(frame: view.bounds) ... textView.textContainer.lineFragmentPadding = 0 textView.sizeToFit() kk@realm.io Remove lineFragmentPadding

Slide 36

Slide 36 text

kk@realm.io Remove lineFragmentPadding

Slide 37

Slide 37 text

let textView = UITextView(frame: view.bounds) ... textView.layoutManager.usesFontLeading = false textView.sizeToFit() kk@realm.io Ignore font.leading

Slide 38

Slide 38 text

kk@realm.io Ignore font.leading @interface NSLayoutManager : NSObject ... // By default, a layout manager will use leading as specified by the font. However, this is not appropriate for most UI text, for which a fixed leading is usually specified by UI layout guidelines. These methods allow the use of the font's leading to be turned off. @property(NS_NONATOMIC_IOSONLY) BOOL usesFontLeading;

Slide 39

Slide 39 text

let textView = UITextView(frame: view.bounds) ... textView.layoutManager.usesFontLeading = false textView.sizeToFit() kk@realm.io Ignore font.leading

Slide 40

Slide 40 text

kk@realm.io Ignore font.leading

Slide 41

Slide 41 text

let size = CGSize(width: textView.bounds.width, height: CGFloat.max) let boundingRect = NSString(string: text).boundingRectWithSize(size, options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: [NSFontAttributeName: font], context: nil) kk@realm.io Note: Including font.leading

Slide 42

Slide 42 text

kk@realm.io Including font.leading

Slide 43

Slide 43 text

kk@realm.io textView.textContainerInset = UIEdgeInsetsZero textView.textContainer.lineFragmentPadding = 0 textView.layoutManager.usesFontLeading = false Reset Default Margins

Slide 44

Slide 44 text

Displaying Rich Text kk@realm.io

Slide 45

Slide 45 text

let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = ceil(font.lineHeight) paragraphStyle.maximumLineHeight = ceil(font.lineHeight) paragraphStyle.lineSpacing = ceil(font.pointSize / 2) let attributes = [ NSFontAttributeName: font, NSForegroundColorAttributeName: UIColor(...), NSParagraphStyleAttributeName: paragraphStyle, ] let attributedText = NSAttributedString(string: text, attributes: attributes) textView.attributedText = attributedText kk@realm.io NSAttributedString

Slide 46

Slide 46 text

kk@realm.io Change Line Height

Slide 47

Slide 47 text

kk@realm.io Change Line Height

Slide 48

Slide 48 text

let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = ceil(font.lineHeight) paragraphStyle.maximumLineHeight = ceil(font.lineHeight) paragraphStyle.lineSpacing = ceil(font.pointSize / 2) let attributes = [ NSFontAttributeName: font, NSForegroundColorAttributeName: UIColor(...), NSParagraphStyleAttributeName: paragraphStyle, ] let attributedText = NSAttributedString(string: text, attributes: attributes) textView.attributedText = attributedText kk@realm.io Control Line Height

Slide 49

Slide 49 text

let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = ceil(font.lineHeight) paragraphStyle.maximumLineHeight = ceil(font.lineHeight) paragraphStyle.lineSpacing = ceil(font.pointSize / 2) kk@realm.io min/maxLineHeight

Slide 50

Slide 50 text

kk@realm.io min/maxLineHeight https://github.com/ibireme/YYText MinimumLineHeight MaximumLineHeight

Slide 51

Slide 51 text

kk@realm.io Line spacing https://github.com/ibireme/YYText

Slide 52

Slide 52 text

kk@realm.io FirstLineHeadIndent https://github.com/ibireme/YYText

Slide 53

Slide 53 text

kk@realm.io TextAlignment https://github.com/ibireme/YYText

Slide 54

Slide 54 text

kk@realm.io Kerning https://github.com/ibireme/YYText

Slide 55

Slide 55 text

Advanced Example of NSAttributedString kk@realm.io

Slide 56

Slide 56 text

kk@realm.io

Slide 57

Slide 57 text

kk@realm.io

Slide 58

Slide 58 text

kk@realm.io

Slide 59

Slide 59 text

kk@realm.io

Slide 60

Slide 60 text

kk@realm.io

Slide 61

Slide 61 text

kk@realm.io

Slide 62

Slide 62 text

kk@realm.io Mathematical Formulas

Slide 63

Slide 63 text

kk@realm.io Mathematical Formulas

Slide 64

Slide 64 text

kk@realm.io Mathematical Formulas

Slide 65

Slide 65 text

kk@realm.io Mathematical Formulas [NSFontAttributeName: UIFont(name: "LatinModernMath-Regular"]

Slide 66

Slide 66 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: 18]

Slide 67

Slide 67 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: -26]

Slide 68

Slide 68 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: -68]

Slide 69

Slide 69 text

kk@realm.io Mathematical Formulas [String(kCTSuperscriptAttributeName): 1]

Slide 70

Slide 70 text

kk@realm.io Mathematical Formulas [NSFontAttributeName: font.scale(x: 0.6, y: 0.6)]

Slide 71

Slide 71 text

kk@realm.io Scaling font extension UIFont { func scale(x x: CGFloat, y: CGFloat) -> UIFont { return transform(CGAffineTransformMakeScale(x, y)) } func transform(matrix: CGAffineTransform) -> UIFont { return UIFont(descriptor: fontDescriptor().fontDescriptorWithMatrix(matrix), size: pointSize) } }

Slide 72

Slide 72 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: 2]

Slide 73

Slide 73 text

kk@realm.io Mathematical Formulas "\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}"

Slide 74

Slide 74 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: 14]

Slide 75

Slide 75 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: -12]

Slide 76

Slide 76 text

kk@realm.io Mathematical Formulas “\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}...”

Slide 77

Slide 77 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: -12]

Slide 78

Slide 78 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: -135]

Slide 79

Slide 79 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: -12]

Slide 80

Slide 80 text

kk@realm.io Mathematical Formulas

Slide 81

Slide 81 text

kk@realm.io Mathematical Formulas

Slide 82

Slide 82 text

kk@realm.io Mathematical Formulas [NSFontAttributeName: UIFont(name: "LatinModernMath-Regular"]

Slide 83

Slide 83 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: -20]

Slide 84

Slide 84 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: -14]

Slide 85

Slide 85 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: -8]

Slide 86

Slide 86 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: -14]

Slide 87

Slide 87 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: 4]

Slide 88

Slide 88 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: -8]

Slide 89

Slide 89 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: -24]

Slide 90

Slide 90 text

kk@realm.io Mathematical Formulas [NSFontAttributeName: font.scale(x: 0.6, y: 0.6)]

Slide 91

Slide 91 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: -20]

Slide 92

Slide 92 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: 10]

Slide 93

Slide 93 text

kk@realm.io Mathematical Formulas [NSFontAttributeName: font.scale(x: 0.6, y: 0.6)]

Slide 94

Slide 94 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: -14]

Slide 95

Slide 95 text

kk@realm.io Mathematical Formulas [String(kCTSuperscriptAttributeName): -1]

Slide 96

Slide 96 text

kk@realm.io Mathematical Formulas [NSFontAttributeName: font.scale(x: 0.6, y: 0.6)]

Slide 97

Slide 97 text

kk@realm.io Mathematical Formulas [String(kCTSuperscriptAttributeName): 1]

Slide 98

Slide 98 text

kk@realm.io Mathematical Formulas [NSFontAttributeName: font.scale(x: 0.6, y: 0.6)]

Slide 99

Slide 99 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: -8]

Slide 100

Slide 100 text

kk@realm.io Mathematical Formulas [NSFontAttributeName: font.scale(x: 1, y: 2.4)]

Slide 101

Slide 101 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: 20]

Slide 102

Slide 102 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: 2]

Slide 103

Slide 103 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: 16]

Slide 104

Slide 104 text

kk@realm.io Mathematical Formulas [NSKernAttributeName: -118]

Slide 105

Slide 105 text

kk@realm.io Mathematical Formulas [NSBaselineOffsetAttributeName: -8]

Slide 106

Slide 106 text

kk@realm.io https://github.com/ kishikawakatsumi/TextKitExamples

Slide 107

Slide 107 text

Summary • No longer use CoreText directly • Carefully to choose font. Text layout is based on font metrics • The most important is constructing NSAttributedString kk@realm.io