Swifty View Controller Presenters

Swifty View Controller Presenters

One major shortcoming of UIKit is that view controllers have too many responsibilities. This talk focuses on one — presenting and dismissing view controllers — and how we can re-examine and redefine the presentation controller API in iOS with a more Swifty API that reduces boilerplate and increases expressivity.

Video:
https://realm.io/news/slug-jesse-squires-swifty-view-controller-presenters/

GitHub project:
https://github.com/jessesquires/PresenterKit

Event:
https://www.meetup.com/swift-language/events/227833264/

Ba6b43b7b6198e2c20cbd348431ca6f4?s=128

Jesse Squires

January 28, 2016
Tweet

Transcript

  1. SWIFTY VIEW CONTROLLER PRESENTERS JESSE SQUIRES JESSESQUIRES.COM • @JESSE_SQUIRES •

    GITHUB/JESSESQUIRES @swiftlybrief
  2. VIEW CONTROLLERS EVERYWHERE

  3. PRESENTATION CONTROLLERS EVERYWHERE

  4. PRESENTATION VS. TRANSITION

  5. What's the difference?

  6. TRANSITION the moving (or animating) from one view controller to

    another view controller
  7. PRESENTATION the ending visual state (or final appearance) of a

    view controller after the transition
  8. BUT...

  9. TRANSITION VS. PRESENTATION Concepts are very interrelated. Presentation API hooks

    into the transitioning API. Slightly coupled in this way, but otherwise nicely decoupled.
  10. PRESENTATION UIPresentationController iOS 8+

  11. UIPresentationController WAT?

  12. UIPresentationController The APIs are very subtle and usually implicit. You

    often use them without knowing it. Typically overlooked. Previously, relevant on iPad only.
  13. UNDERSTANDING THE PRESENTATION API

  14. RESPONSIBILITIES ▸ Positioning ▸ Content and "Chrome" ▸ Adaption ▸

    Animation Intended to be reusable
  15. 3 PHASES 1. Presentation (moving onscreen)* 2. Management (size class

    changes, device rotation) 3. Dismissal (moving offscreen)* *Transitioning
  16. EXAMPLES

  17. None
  18. None
  19. None
  20. UIPresentationController Subtle and Implicit UIModalPresentationStyle // just set an enum!

    self.modalPresentationStyle = .FullScreen self.modalPresentationStyle = .Popover
  21. None
  22. PRESENTING func presentViewController(_, animated:, completion:) func pushViewController(_, animated:) func showViewController(_,

    sender:) func showDetailViewController(_, sender:)
  23. DISMISSING func dismissViewControllerAnimated(_, completion:) func popViewControllerAnimated(_ animated:) -> UIViewController?

  24. Special PRESENTATIONS

  25. UIPresentationController ▸ UIAlertController ▸ UISearchController ▸ UIPopoverPresentationController (explicit!) Unified, consistent

    APIs. All view controllers with custom presentation controllers.
  26. UIPopoverPresentationController The only custom presentation controller publicly available in UIKit

    // Current UIViewController APIs self.presentationController self.popoverPresentationController
  27. PRIVATE API // Modal styles: .FullScreen, .FormSheet, .PageSheet, etc. _UIFullscreenPresentationController

    // Alerts _UIAlertControllerAlertPresentationController // ActionSheet on iPhone _UIAlertControllerActionSheetCompactPresentationController // ActionSheet on iPad (popover) _UIAlertControllerActionSheetRegularPresentationController
  28. API SUMMARY ▸ 4 methods to display a view controller

    ▸ Set styles via an enum value ▸ Use popoverPresentationController directly ▸ Provide a custom Presentation Controller
  29. The API is easy to misuse.

  30. #SORRYNOTSORRY

  31. HOW TO USE CUSTOM PRESENTATION CONTROLLERS

  32. CUSTOM PRESENTATION CONTROLLERS 1. Subclass UIPresentationController 2. Vend controller via

    transitioning API !
  33. 1. SUBCLASS: TRANSITIONING AND CHROME func presentationTransitionWillBegin() func dismissalTransitionWillBegin()

  34. 1. SUBCLASS: POSITIONING func sizeForChildContentContainer(_, withParentContainerSize:) -> CGSize func frameOfPresentedViewInContainerView()

    -> CGRect
  35. 1. SUBCLASS: ADAPTIVITY func adaptivePresentationStyle() -> UIModalPresentationStyle func shouldPresentInFullscreen() ->

    Bool func containerViewWillLayoutSubviews()
  36. 2. VEND CONTROLLER UIViewControllerTransitioningDelegate Presenting view controller conforms to delegate

    Set this delegate on the Presented view controller let vc = MyViewController() vc.transitioningDelegate = self
  37. 2. VEND CONTROLLER UIViewControllerTransitioningDelegate func presentationControllerForPresentedViewController(_, presentingViewController:, sourceViewController:) -> UIPresentationController?

  38. Demo

  39. BETTER THAN VIEW CONTROLLER CONTAINMENT

  40. Let's build a micro-library ▸ Refine this API ▸ Make

    it Swifty
  41. enum PresentationType { case Modal(NavigationStyle, UIModalPresentationStyle, UIModalTransitionStyle) case Popover(PopoverConfig) case

    Push case Show case ShowDetail(NavigationStyle) case Custom(UIViewControllerTransitioningDelegate) }
  42. enum NavigationStyle { case None case WithNavigation }

  43. struct PopoverConfig { enum Source { case BarButtonItem(UIBarButtonItem) case View(UIView)

    } let source: Source let arrowDirection: UIPopoverArrowDirection let delegate: UIPopoverPresentationControllerDelegate? }
  44. extension UIViewController { // maps PresentationType to UIKit properties and

    methods func presentViewController( controller: UIViewController, type: PresentationType, animated: Bool = true) }
  45. USAGE presentViewController(vc, type: .Push) let config = PopoverConfig(source: .View(v)) presentViewController(vc,

    type: .Popover(config)) let type = .Modal(.WithNavigation, .FullScreen, .CoverVertical) presentViewController(vc, type: type) presentViewController(vc, type: .Custom(self))
  46. Swifty API ▸ More expressive ▸ More concise ▸ Single

    "entry point" to API ▸ More structured (less likely to misuse)
  47. Additional resources: ▸ WWDC 2014 "A Look Inside Presentation Controllers"

    ▸ pspdfkit.com/blog/2015/presentation-controllers/ ▸ petersteinberger.com/blog/2015/uipresentationcontroller-popover- detection/
  48. Thank you!

  49. QUESTIONS? JESSESQUIRES.COM • @JESSE_SQUIRES • GITHUB/JESSESQUIRES