Upgrade to Pro — share decks privately, control downloads, hide ads and more …

BonMot @ MacTechGroup Boston 2017

BonMot @ MacTechGroup Boston 2017

Learn about BonMot, a library for making beautiful typography on iOS. Full Keynote deck is posted at https://cl.ly/kKYA.

Zev Eisenberg

May 05, 2017
Tweet

More Decks by Zev Eisenberg

Other Decks in Technology

Transcript

  1. Lorem Ipsum & the Dolor Sit Amets July 30, 1980

    8:00 pm Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Lorem Ipsum & the Dolor Sit Amets Wednesday, July 30, 1980
 8:00 pm Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
  2. Adobe Illustrator OpenType Panel Figure Style Figure Position Contextual Alternates

    Discretionary Ligatures Swash Stylistic Alternates Titling Alternates Ordinals Fractions Standard Ligatures
  3. ¶ Unpredictable styling of common views ¶ NSAttributedString is hard

    to use ¶ Hard to wrap images with text ¶ Hard to style ranges of strings ¶ Special characters are hard to read ¶ Dynamic Type API is limited
  4. ¶ Unpredictable styling of common views UILabel font lineBreakMode shadowColor

    shadowOffset text textAlignment textColor UITextField font - - - text textAlignment textColor UIButton - - titleShadowColor - title - titleColor +titleLabel
  5. ¶ NSAttributedString is hard to use let label = UILabel()

    
 let paragraphStyle = NSMutableParagraphStyle()
 paragraphStyle.lineHeightMultiple = 0.7
 paragraphStyle.alignment = .center
 let attributes = [
 NSFontAttributeName: UIFont.systemFont(ofSize: 150),
 NSForegroundColorAttributeName: UIColor.red,
 NSParagraphStyleAttributeName: paragraphStyle,
 ]
 label.attributedText = NSAttributedString(
 string: "Real Artists Ship",
 attributes: attributes) label.numberOfLines = 0 Real Artists Ship
  6. ¶ NSAttributedString is hard to use let label = UILabel()


    let style = StringStyle(
 .font(UIFont.systemFont(ofSize: 150)),
 .color(.red),
 .lineHeightMultiple(0.7),
 .alignment(.center)
 )
 let string = "Real Artists Ship".styled(with: style)
 label.attributedText = string label.numberOfLines = 0 easy Real Artists Ship
  7. let label = UILabel()
 let style = StringStyle(
 .font(UIFont.systemFont(ofSize: 150)),


    .color(.red),
 .lineHeightMultiple(0.7),
 .alignment(.center),
 .tracking(.point(15))
 )
 let string = "Real Artists Ship".styled(with: style)
 label.attributedText = string Real Artists Ship ¶ NSAttributedString is hard to use easy
  8. let label = UILabel()
 let style = StringStyle(
 .font(UIFont.systemFont(ofSize: 150)),


    .color(.red),
 .lineHeightMultiple(0.7),
 .alignment(.center),
 .tracking(.adobe(1000))
 )
 let string = "Real Artists Ship".styled(with: style)
 label.attributedText = string ¶ NSAttributedString is hard to use easy Real Artists Ship
  9. Figure Styles $6.28 $3.18 $5.30 $7.17 $9.58 proportional
 uppercase $6.28

    $3.18 $5.30 $7.17 $9.58 monospaced
 uppercase
  10. Figure Styles In 1768, jugglers first appeared as top acts

    in a circus when Philip Astley hired jugglers to perform with his troupe in England. In 1793, juggling arrived to the circuses of the United States. proportional lowercase http://www.topendsports.com/juggling/history.htm proportional uppercase In 1768, jugglers first appeared as top acts in a circus when Philip Astley hired jugglers to perform with his troupe in England. In 1793, juggling arrived to the circuses of the United States.
  11. Figure Styles In 1768, jugglers first appeared as top acts

    in a circus when Philip Astley hired jugglers to perform with his troupe in England. In 1793, juggling arrived to the circuses of the United States. proportional lowercase http://www.topendsports.com/juggling/history.htm proportional uppercase In 1768, jugglers first appeared as top acts in a circus when Philip Astley hired jugglers to perform with his troupe in England. In 1793, juggling arrived to the circuses of the United States.
  12. Figure Styles In 1768, jugglers first appeared as top acts

    in a circus when Philip Astley hired jugglers to perform with his troupe in England. In 1793, juggling arrived to the circuses of the United States. proportional lowercase http://www.topendsports.com/juggling/history.htm proportional uppercase In 1768, jugglers first appeared as top acts in a circus when Philip Astley hired jugglers to perform with his troupe in England. In 1793, juggling arrived to the circuses of the United States. let originalDescriptor = myFont.fontDescriptor let featureSettings = [ [ UIFontFeatureTypeIdentifierKey: kNumberSpacingType, UIFontFeatureSelectorIdentifierKey: kMonospacedNumbersSelector, ], ] let attributes = [ UIFontDescriptorFeatureSettingsAttribute: featureSettings, ] let fontDescriptor = originalDescriptor.addingAttributes(attributes) let font = UIFont(descriptor: fontDescriptor, size: 0)
  13. let label = UILabel()
 let style = StringStyle(
 .font(UIFont.systemFont(ofSize: 150)),


    .color(.red),
 .lineHeightMultiple(0.7),
 .alignment(.center),
 .tracking(.adobe(1000)),
 .numberSpacing(.monospaced), .numberCase(.upper)
 )
 let string = "Real Artists Ship".styled(with: style)
 label.attributedText = string ¶ NSAttributedString is hard to use easy Real Artists Ship
  14. ¶ Hard to wrap images with text let attachment =

    NSTextAttachment() attachment.image = attachment.bounds = CGRect(origin: .zero, size: .size) let imageString = NSAttributedString(attachment: attachment) let fullString = NSMutableAttributedString(string: " is awesome!") fullString.insert(imageString, at: 0) UNCAUGHT EXCEPTION (NSInvalidUnarchiveOperationException): *** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (UIImage) for key (NS.image); the class may be defined in source code or a library that is not linked rdar://30605012 is awesome!
  15. is awesome! ¶ Hard to wrap images with text Surprisingly

    easy let fullString = NSAttributedString.composed(of: [ , " is awesome!", ]) let attachment = NSTextAttachment() attachment.image = attachment.bounds = CGRect(origin: .zero, size: .size) let imageString = NSAttributedString(attachment: attachment) let fullString = NSMutableAttributedString(string: " is awesome!") fullString.insert(imageString, at: 0)
  16. ¶ Hard to style ranges of strings I went to

    Boston, and it was not too cold! Je suis allé à Boston, et
 il ne faisait pas trop froid!
  17. 8:21 PM - 13 Mar 2015 NSAttributedString is great because

    it’s the result of years of research that have shown coupling between data and presentation to be ideal. @hyperspacemark Mark Adams ¶ Hard to style ranges of strings
  18. ¶ Hard to style ranges of strings let string =

    "I went to Boston, and it was <strong>not</strong> too cold!"
 let strong = StringStyle(
 .font(myBoldFont)
 )
 let style = StringStyle(
 .font(myNormalFont),
 .xmlRules([
 .style("strong", strong),
 ]))
 let attributed = string.styled(with: style) Trivial I went to Boston, and it was not too cold!
  19. ¶ Hard to style ranges of strings let string =

    "Je suis allé à Boston, et il <strong>ne</strong> faisait <strong>pas</strong> trop froid!"
 let strong = StringStyle(
 .font(myBoldFont)
 )
 let style = StringStyle(
 .font(myNormalFont),
 .xmlRules([
 .style("strong", strong),
 ]))
 let attributed = string.styled(with: style) Trivial Je suis allé à Boston, et
 il ne faisait pas trop froid!
  20. ¶ Special characters are hard to read func testSpecialCharacters() {

    // U+00A0: no-break space let test = "Swift\u{00A0}is\u{00A0}awesome!" XCTAssertEqual(test, "Swift is awesome!") } ("Swift is awesome!") is not equal to ("Swift is awesome!")
  21. ¶ Special characters are hard to read func testSpecialCharacters() {


    let string = "Swift<BON:noBreakSpace/>is<BON:noBreakSpace/>awesome!" let attributed = string.styled(with: .xmlRules([])) let test = attributed.bonMotDebugString XCTAssertEqual(test, "Swift is awesome!")
 } painless ("Swift<BON:noBreakSpace/>is<BON:noBreakSpace/>awesome!") is not equal to ("Swift is awesome!")
  22. ¶ Dynamic Type API is limited let font = UIFont.preferredFont(forTextStyle:

    .headline)
 NotificationCenter.default.addObserver(
 self,
 selector: #selector(changedSize),
 name: .UIContentSizeCategoryDidChange,
 object: nil)
 override func traitCollectionDidChange(_ previous: UITraitCollection?) {
 super.traitCollectionDidChange(previous)
 ... // iOS 10+
 }
  23. ¶ Dynamic Type API is limited UIApplication.shared.enableAdaptiveContentSizeMonitor()
 
 let style

    = StringStyle(
 .font(inputFont),
 .adapt(.body) // or .adapt(.control)
 ) rad
  24. ¶ Dynamic Type API is limited rad 0 5 10

    15 20 25 30 35 40 45 50 55 60 XS S M L (default) XL XXL XXXL AccessibilityM AccessibilityL AccessibilityXL AccessibilityXXL AccessibilityXXXL Caption2 Headline Caption1 Title2 Footnote Title3 Callout Body Subhead
  25. ¶ Unpredictable styling of common views ¶ NSAttributedString is hard

    to use ¶ Hard to wrap images with text ¶ Hard to style ranges of strings ¶ Special characters are hard to read ¶ Dynamic Type API is limited rad painless Trivial Surprisingly easy Predictable-ish easy
  26. struct StringStyle { var font: BONFont? var backgroundColor: BONColor? var

    color: BONColor? var underline: (NSUnderlineStyle, BONColor?)? var strikethrough: (NSUnderlineStyle, BONColor?)? var baselineOffset: CGFloat? var lineSpacing: CGFloat? var paragraphSpacingAfter: CGFloat? var alignment: NSTextAlignment? var firstLineHeadIndent: CGFloat? var lineHeightMultiple: CGFloat? // ✂ snip 40 lines var numberCase: NumberCase? var numberSpacing: NumberSpacing? var tracking: Tracking? } StringStyle (360 lines)
  27. StringStyle (360 lines) attributes.update(possibleValue: font, forKey: NSFontAttributeName) attributes.update(possibleValue: link, forKey:

    NSLinkAttributeName) attributes.update(possibleValue: backgroundColor, forKey: NSBackgroundColorAttributeName) attributes.update(possibleValue: color, forKey: NSForegroundColorAttributeName) attributes.update(possibleValue: underline?.0.rawValue, forKey: NSUnderlineStyleAttributeName) attributes.update(possibleValue: underline?.1, forKey: NSUnderlineColorAttributeName) // etc
  28. StringStyle (360 lines) var style = StringStyle() style.font = UIFont.systemFont(ofSize:

    150) style.color = .red style.lineHeightMultiple = 0.7 style.alignment = .center let string = "Swift is awesome!".styled(with: style)
  29. StringStyle.Part (300 lines) extension StringStyle { public enum Part {

    case font(BONFont) case backgroundColor(BONColor) case color(BONColor) case underline(NSUnderlineStyle, BONColor?) case strikethrough(NSUnderlineStyle, BONColor?) case baselineOffset(CGFloat) case alignment(NSTextAlignment) case tracking(Tracking) case lineSpacing(CGFloat) case paragraphSpacingAfter(CGFloat) case firstLineHeadIndent(CGFloat) case numberSpacing(NumberSpacing) case numberCase(NumberCase) case fractions(Fractions) // ✂ snip many lines } }
  30. StringStyle.Part (300 lines) extension StringStyle { public init(_ parts: Part...)

    { self.init(parts) } public init(_ parts: [Part]) { self.init() for part in parts { update(part: part) } } }
  31. StringStyle.Part (300 lines) let style = StringStyle( .font(UIFont.systemFont(ofSize: 150)), .color(.red),

    .lineHeightMultiple(0.7), .alignment(.center) ) let string = "Swift is awesome!".styled(with: style)
  32. iOS + macOS + tvOS + watchOS Compatibility (50 lines)

    #if os(OSX) import AppKit public typealias BONColor = NSColor public typealias BONImage = NSImage public typealias BONTextField = NSTextField public typealias BONFont = NSFont public typealias BONFontDescriptor = NSFontDescriptor let BONFontDescriptorFeatureSettingsAttribute = NSFontFeatureSettingsAttribute let BONFontFeatureTypeIdentifierKey = NSFontFeatureTypeIdentifierKey let BONFontFeatureSelectorIdentifierKey = NSFontFeatureSelectorIdentifierKey #else import UIKit public typealias BONColor = UIColor public typealias BONImage = UIImage public typealias BONFont = UIFont public typealias BONFontDescriptor = UIFontDescriptor let BONFontDescriptorFeatureSettingsAttribute = UIFontDescriptorFeatureSettingsAttribute let BONFontFeatureTypeIdentifierKey = UIFontFeatureTypeIdentifierKey let BONFontFeatureSelectorIdentifierKey = UIFontFeatureSelectorIdentifierKey #if os(iOS) || os(tvOS) public typealias BONTextField = UITextField #endif #endif