Save 37% off PRO during our Black Friday Sale! »

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!

D3c5f7382824133c2718c8effb5894fb?s=128

Ayaka Nonaka

April 29, 2016
Tweet

Transcript

  1. Clean Layout with ✨ iOS 9 ✨ @ayanonagon

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

  3. None
  4. WWDC 2016

  5. ! iOS 10 !

  6. ! iOS 8 !

  7. ✨ iOS 9 ✨

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

    the audience
  9. iOS 9 • 3D Touch • SFSafariViewController • CoreSpotlight.framework •

    Contacts.framework & ContactsUI.framework (ABAddressBook !)
  10. UIKit?

  11. UIKit • Better right-to-left language support • UIUserNotificationAction now has

    a behavior property • NSLayoutAnchor • UILayoutGuide • UIStackView
  12. Today • NSLayoutAnchor • UILayoutGuide • UIStackView

  13. Clean Layout with ✨ iOS 9 ✨ @ayanonagon

  14. Disclaimer: I do everything in code.

  15. !

  16. Cleaner Safer Simpler

  17. Fun!

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

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

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

  21. NSLayoutConstraint.init NSLayoutConstraint(item: whyIsThis, attribute: .Height, relatedBy: .Equal, toItem: soVerbose, attribute:

    .NotAnAttribute, multiplier: 1.0, constant: 44.0)
  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)]-|"
  23. “I want this view to be top-aligned with this other

    view.”
  24. NSLayoutConstraint(item: view, attribute: .Top, relatedBy: .Equal, toItem: otherView, attribute: .Top,

    multiplier: 1.0, constant: 0.0)
  25. ✨ NSLayoutAnchor ✨

  26. NSLayoutConstraint(item: view, attribute: .Top, relatedBy: .Equal, toItem: otherView, attribute: .Top,

    multiplier: 1.0, constant: 0.0)
  27. view.topAnchor.constraintEqualToAnchor(otherView.topAnchor)

  28. NSLayoutConstraint(item: view, attribute: .Top, relatedBy: .Equal, toItem: otherView, attribute: .Top,

    multiplier: 1.0, constant: 0.0) // vs. view.topAnchor.constraintEqualToAnchor(otherView.topAnchor)
  29. “I want this view to have a height of 44.”

  30. NSLayoutConstraint(item: view, attribute: .Height, relatedBy: .Equal, toItem: nil, // meh

    attribute: .NotAnAttribute, // wat multiplier: 1.0, // ugh constant: 44)
  31. view.heightAnchor.constraintEqualToConstant(44)

  32. NSLayoutConstraint(item: view, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,

    multiplier: 1.0, constant: 44) // vs. view.heightAnchor.constraintEqualToConstant(44)
  33. “I want the top of this view to be aligned

    with the left side of this other view.” — me, on a sleepy day !
  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. !
  35. [view.topAnchor constraintEqualToAnchor:otherView.leftAnchor]; Doesn’t make sense, so compiler emits a warning!

    !
  36. None
  37. None
  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)
  39. What happened to Swift? !

  40. What happened to Swift? Doesn’t work for Swift because not

    all Objective-C generics have been brought over to Swift yet.
  41. “I want this view to be top-aligned with this other

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

  43. ✨ UILayoutGuide ✨

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

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

    view and I want some padding.”
  46. let margins = otherView.layoutMarginsGuide view.topAnchor.constraintEqualToAnchor(margins.topAnchor)

  47. “I want all of these views together to be centered

    in the superview.”
  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.
  49. Problems • Clutters the view hierarchy. • The container view

    participates in the responder chain.
  50. ✨ UILayoutGuide (again!) ✨

  51. UILayoutGuide • Not a member of the view hierarchy. •

    Does not participate in the responder chain.
  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.
  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.
  54. let guide = UILayoutGuide() guide.addSubview(view1) guide.addSubview(view2) // view3, … view.addLayoutGuide(guide)

  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), ])
  56. Spacing with UILayoutGuide

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

  59. “… and I want to be able to show and

    hide the middle view.” — probably a designer
  60. None
  61. None
  62. Method 1 1.Make the height constraint of the middle view

    zero. 2.Deal with double padding issues.
  63. None
  64. None
  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.
  66. None
  67. None
  68. Method 3 1.Use a collection view to do your layout.

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

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

  71. ✨ UIStackView ✨

  72. None
  73. “I want to stack three views vertically and I want

    to be able to show and hide the middle view.”
  74. let stackView = UIStackView() stackView.axis = .Vertical stackView.addArrangedSubview(view1) stackView.addArrangedSubview(view2) stackView.addArrangedSubview(view3)

    view2.hidden = true // or false
  75. !

  76. None
  77. None
  78. None
  79. None
  80. None
  81. None
  82. TZStackView • Compatible with iOS 7.x and iOS 8.x •

    But no Storyboard support • :%s/TZStackView/UIStackView/g
  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
  84. Thanks! ! iOS 8 !

  85. Questions? ayaka@nonaka.me @ayanonagon

  86. None