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

Clean Layout with iOS 9

Clean Layout with iOS 9

Talk given 29 Apr 2016 at NSNorth Toronto

WWDC 2016 is just around the corner, and there’s probably going to be a bunch of cool stuff announced (maybe even a Siri API?!). But you know what’s more exciting than iOS 10? We can drop iOS 8 support now! And that means that we can start using and celebrating the iOS 9 features that we announced last year. :tada: Honestly, I really didn’t enjoy UI programming until Swift and iOS 9 were available. Now I’ve found myself actually enjoying UI programming. I hope to share some of that excitement with you in this talk.

This talk will go over:
* NSLayoutAnchor
* UILayoutGuide
* UIStackView

Hope you enjoy!

Ayaka Nonaka

April 29, 2016
Tweet

More Decks by Ayaka Nonaka

Other Decks in Technology

Transcript

  1. Clean Layout
    with ✨ iOS 9 ✨
    @ayanonagon

    View Slide

  2. Hi, I’m Ayaka.
    @ayanonagon
    NSNorth 2016

    View Slide

  3. View Slide

  4. WWDC 2016

    View Slide

  5. ! iOS 10 !

    View Slide

  6. ! iOS 8 !

    View Slide

  7. ✨ iOS 9 ✨

    View Slide

  8. “But we still
    support iOS 7. !”
    — somebody in the audience

    View Slide

  9. iOS 9
    • 3D Touch
    • SFSafariViewController
    • CoreSpotlight.framework
    • Contacts.framework & ContactsUI.framework
    (ABAddressBook !)

    View Slide

  10. UIKit?

    View Slide

  11. UIKit
    • Better right-to-left language support
    • UIUserNotificationAction now has a behavior
    property
    • NSLayoutAnchor
    • UILayoutGuide
    • UIStackView

    View Slide

  12. Today
    • NSLayoutAnchor
    • UILayoutGuide
    • UIStackView

    View Slide

  13. Clean Layout
    with ✨ iOS 9 ✨
    @ayanonagon

    View Slide

  14. Disclaimer: I do everything in code.

    View Slide

  15. !

    View Slide

  16. Cleaner
    Safer
    Simpler

    View Slide

  17. Fun!

    View Slide

  18. VFL
    "|-50-[rememberThis]-50-|"
    "|-[omg]-[what]-[isThisView(>=20)]-|"

    View Slide

  19. V(isual) F(ormat) L(anguage)
    "|-50-[rememberThis]-50-|"
    "|-[omg]-[what]-[isThisView(>=20)]-|"

    View Slide

  20. V(ery) F(ragile) L(anguage)
    "|-50-typos]-50-|"
    "|-[omg]-typs]-[everywhere(>=20)-|"

    View Slide

  21. NSLayoutConstraint.init
    NSLayoutConstraint(item: whyIsThis,
    attribute: .Height,
    relatedBy: .Equal,
    toItem: soVerbose,
    attribute: .NotAnAttribute,
    multiplier: 1.0,
    constant: 44.0)

    View Slide

  22. NSLayoutConstraint(item: whyIsThis,
    attribute: .Height,
    relatedBy: .Equal,
    toItem: soVerbose,
    attribute: .NotAnAttribute,
    multiplier: 1.0,
    constant: 44.0)
    "|-50-[rememberThis]-50-|"
    "|-[omg]-[what]-[isThisView(>=20)]-|"

    View Slide

  23. “I want this view
    to be top-aligned
    with this other
    view.”

    View Slide

  24. NSLayoutConstraint(item: view,
    attribute: .Top,
    relatedBy: .Equal,
    toItem: otherView,
    attribute: .Top,
    multiplier: 1.0,
    constant: 0.0)

    View Slide

  25. ✨ NSLayoutAnchor ✨

    View Slide

  26. NSLayoutConstraint(item: view,
    attribute: .Top,
    relatedBy: .Equal,
    toItem: otherView,
    attribute: .Top,
    multiplier: 1.0,
    constant: 0.0)

    View Slide

  27. view.topAnchor.constraintEqualToAnchor(otherView.topAnchor)

    View Slide

  28. NSLayoutConstraint(item: view,
    attribute: .Top,
    relatedBy: .Equal,
    toItem: otherView,
    attribute: .Top,
    multiplier: 1.0,
    constant: 0.0)
    // vs.
    view.topAnchor.constraintEqualToAnchor(otherView.topAnchor)

    View Slide

  29. “I want this view
    to have a height of
    44.”

    View Slide

  30. NSLayoutConstraint(item: view,
    attribute: .Height,
    relatedBy: .Equal,
    toItem: nil, // meh
    attribute: .NotAnAttribute, // wat
    multiplier: 1.0, // ugh
    constant: 44)

    View Slide

  31. view.heightAnchor.constraintEqualToConstant(44)

    View Slide

  32. NSLayoutConstraint(item: view,
    attribute: .Height,
    relatedBy: .Equal,
    toItem: nil,
    attribute: .NotAnAttribute,
    multiplier: 1.0,
    constant: 44)
    // vs.
    view.heightAnchor.constraintEqualToConstant(44)

    View Slide

  33. “I want the top of
    this view to be
    aligned with the
    left side of this
    other view.”
    — me, on a sleepy day !

    View Slide

  34. [NSLayoutConstraint constraintWithItem:view
    attribute:NSLayoutAttributeTop
    relatedBy:NSLayoutRelationEqual
    toItem:otherView
    attribute:NSLayoutAttributeLeft
    multiplier:1.0
    constant:0.0];
    Doesn’t make sense, but compiles without warning.
    !

    View Slide

  35. [view.topAnchor constraintEqualToAnchor:otherView.leftAnchor];
    Doesn’t make sense, so compiler emits a warning!
    !

    View Slide

  36. View Slide

  37. View Slide

  38. Type Safety
    • Dimension anchors (e.g. heightAnchor,
    widthAnchor)
    • X-axis anchors (e.g. leadingAnchor,
    trailingAnchor, leftAnchor, rightAnchor,
    centerXAnchor)
    • Y-axis anchors (e.g. topAnchor, bottomAnchor,
    centerYAnchor, firstBaselineAnchor,
    lastBaselineAnchor)

    View Slide

  39. What happened to Swift? !

    View Slide

  40. What happened to Swift?
    Doesn’t work for Swift because not all Objective-C
    generics have been brought over to Swift yet.

    View Slide

  41. “I want this view
    to be top-aligned
    with this other
    view.”

    View Slide

  42. “… and I also want
    some padding.”

    View Slide

  43. ✨ UILayoutGuide ✨

    View Slide

  44. UIView
    • layoutMargins (UIEdgeInsets)
    • layoutMarginsGuide (UILayoutGuide) ✨ iOS 9 ✨

    View Slide

  45. “I want this view
    to be top-aligned
    with this other
    view and I want
    some padding.”

    View Slide

  46. let margins = otherView.layoutMarginsGuide
    view.topAnchor.constraintEqualToAnchor(margins.topAnchor)

    View Slide

  47. “I want all of
    these views
    together to be
    centered in the
    superview.”

    View Slide

  48. Centering
    1.Put all the views in a dummy container view.
    2.Add the container view into the view hierarchy.
    3.Center the container view.

    View Slide

  49. Problems
    • Clutters the view hierarchy.
    • The container view participates in the
    responder chain.

    View Slide

  50. ✨ UILayoutGuide (again!) ✨

    View Slide

  51. UILayoutGuide
    • Not a member of the view hierarchy.
    • Does not participate in the responder chain.

    View Slide

  52. UIView Centering
    1.Put all the views in a dummy container view.
    2.Add the container view into the view hierarchy.
    3.Center the container view.

    View Slide

  53. UILayoutGuide Centering
    1.Put all the views in a container layout guide.
    2.Add the layout guide to the view hierarchy.
    3.Center the layout guide.

    View Slide

  54. let guide = UILayoutGuide()
    guide.addSubview(view1)
    guide.addSubview(view2)
    // view3, …
    view.addLayoutGuide(guide)

    View Slide

  55. // Position the views in the layout guide.
    NSLayoutConstraint.activateConstraints([
    view1.topAnchor.constraintEqualToAnchor(guide.topAnchor),
    view1.leadingAnchor.constraintEqualToAnchor(guide.leadingAnchor),
    // view2, view3, …
    ])
    // Position the layout guide in the main view.
    NSLayoutConstraint.activateConstraints([
    guide.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor),
    guide.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor),
    ])

    View Slide

  56. Spacing with UILayoutGuide

    View Slide

  57. View Slide

  58. “I want to stack
    three views
    vertically.”

    View Slide

  59. “… and I want to be
    able to show and
    hide the middle
    view.”
    — probably a designer

    View Slide

  60. View Slide

  61. View Slide

  62. Method 1
    1.Make the height constraint of the middle view
    zero.
    2.Deal with double padding issues.

    View Slide

  63. View Slide

  64. View Slide

  65. Method 2
    1.Define a vertical constraint between the top
    most view and the bottom most view.
    2.Shrink that constraint’s height to be the
    padding amount.
    3.Hide the middle view.

    View Slide

  66. View Slide

  67. View Slide

  68. Method 3
    1.Use a collection view to do your layout.
    2.Update data source.

    View Slide

  69. What year is it?!
    (›°□°ʣ›ớ ᵲᴸᵲ

    View Slide

  70. Let’s use iOS 9.
    ┬──┬ ϊ( ʄ-ʄϊ)

    View Slide

  71. ✨ UIStackView ✨

    View Slide

  72. View Slide

  73. “I want to stack
    three views
    vertically and I
    want to be able to
    show and hide the
    middle view.”

    View Slide

  74. let stackView = UIStackView()
    stackView.axis = .Vertical
    stackView.addArrangedSubview(view1)
    stackView.addArrangedSubview(view2)
    stackView.addArrangedSubview(view3)
    view2.hidden = true // or false

    View Slide

  75. !

    View Slide

  76. View Slide

  77. View Slide

  78. View Slide

  79. View Slide

  80. View Slide

  81. View Slide

  82. TZStackView
    • Compatible with iOS 7.x and iOS 8.x
    • But no Storyboard support
    • :%s/TZStackView/UIStackView/g

    View Slide

  83. Recap
    • Cleaner and more type-safe layouts via
    NSLayoutAnchor
    • Simpler view hierarchies and responder chain
    via UILayoutGuide
    • Flexible (and easier to understand) layouts via
    UIStackView

    View Slide

  84. Thanks!
    ! iOS 8 !

    View Slide

  85. Questions?
    [email protected]
    @ayanonagon

    View Slide

  86. View Slide