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

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/

Jesse Squires

January 28, 2016
Tweet

More Decks by Jesse Squires

Other Decks in Programming

Transcript

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

    View Slide

  2. VIEW CONTROLLERS
    EVERYWHERE

    View Slide

  3. PRESENTATION CONTROLLERS
    EVERYWHERE

    View Slide

  4. PRESENTATION
    VS.
    TRANSITION

    View Slide

  5. What's the difference?

    View Slide

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

    View Slide

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

    View Slide

  8. BUT...

    View Slide

  9. TRANSITION VS. PRESENTATION
    Concepts are very interrelated.
    Presentation API hooks into the transitioning API.
    Slightly coupled in this way, but otherwise nicely decoupled.

    View Slide

  10. PRESENTATION
    UIPresentationController
    iOS 8+

    View Slide

  11. UIPresentationController
    WAT?

    View Slide

  12. UIPresentationController
    The APIs are very subtle and usually implicit.
    You often use them without knowing it.
    Typically overlooked.
    Previously, relevant on iPad only.

    View Slide

  13. UNDERSTANDING
    THE PRESENTATION API

    View Slide

  14. RESPONSIBILITIES
    ▸ Positioning
    ▸ Content and "Chrome"
    ▸ Adaption
    ▸ Animation
    Intended to be reusable

    View Slide

  15. 3 PHASES
    1. Presentation (moving onscreen)*
    2. Management (size class changes, device rotation)
    3. Dismissal (moving offscreen)*
    *Transitioning

    View Slide

  16. EXAMPLES

    View Slide

  17. View Slide

  18. View Slide

  19. View Slide

  20. UIPresentationController
    Subtle and Implicit
    UIModalPresentationStyle
    // just set an enum!
    self.modalPresentationStyle = .FullScreen
    self.modalPresentationStyle = .Popover

    View Slide

  21. View Slide

  22. PRESENTING
    func presentViewController(_, animated:, completion:)
    func pushViewController(_, animated:)
    func showViewController(_, sender:)
    func showDetailViewController(_, sender:)

    View Slide

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

    View Slide

  24. Special
    PRESENTATIONS

    View Slide

  25. UIPresentationController
    ▸ UIAlertController
    ▸ UISearchController
    ▸ UIPopoverPresentationController (explicit!)
    Unified, consistent APIs.
    All view controllers with custom presentation controllers.

    View Slide

  26. UIPopoverPresentationController
    The only custom presentation controller publicly available in UIKit
    // Current UIViewController APIs
    self.presentationController
    self.popoverPresentationController

    View Slide

  27. PRIVATE API
    // Modal styles: .FullScreen, .FormSheet, .PageSheet, etc.
    _UIFullscreenPresentationController
    // Alerts
    _UIAlertControllerAlertPresentationController
    // ActionSheet on iPhone
    _UIAlertControllerActionSheetCompactPresentationController
    // ActionSheet on iPad (popover)
    _UIAlertControllerActionSheetRegularPresentationController

    View Slide

  28. API SUMMARY
    ▸ 4 methods to display a view controller
    ▸ Set styles via an enum value
    ▸ Use popoverPresentationController directly
    ▸ Provide a custom Presentation Controller

    View Slide

  29. The API is easy to misuse.

    View Slide

  30. #SORRYNOTSORRY

    View Slide

  31. HOW TO USE
    CUSTOM PRESENTATION
    CONTROLLERS

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  37. 2. VEND CONTROLLER
    UIViewControllerTransitioningDelegate
    func presentationControllerForPresentedViewController(_,
    presentingViewController:,
    sourceViewController:) -> UIPresentationController?

    View Slide

  38. Demo

    View Slide

  39. BETTER THAN VIEW
    CONTROLLER CONTAINMENT

    View Slide

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

    View Slide

  41. enum PresentationType {
    case Modal(NavigationStyle, UIModalPresentationStyle, UIModalTransitionStyle)
    case Popover(PopoverConfig)
    case Push
    case Show
    case ShowDetail(NavigationStyle)
    case Custom(UIViewControllerTransitioningDelegate)
    }

    View Slide

  42. enum NavigationStyle {
    case None
    case WithNavigation
    }

    View Slide

  43. struct PopoverConfig {
    enum Source {
    case BarButtonItem(UIBarButtonItem)
    case View(UIView)
    }
    let source: Source
    let arrowDirection: UIPopoverArrowDirection
    let delegate: UIPopoverPresentationControllerDelegate?
    }

    View Slide

  44. extension UIViewController {
    // maps PresentationType to UIKit properties and methods
    func presentViewController(
    controller: UIViewController,
    type: PresentationType,
    animated: Bool = true)
    }

    View Slide

  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))

    View Slide

  46. Swifty API
    ▸ More expressive
    ▸ More concise
    ▸ Single "entry point" to API
    ▸ More structured
    (less likely to misuse)

    View Slide

  47. Additional resources:
    ▸ WWDC 2014 "A Look Inside Presentation Controllers"
    ▸ pspdfkit.com/blog/2015/presentation-controllers/
    ▸ petersteinberger.com/blog/2015/uipresentationcontroller-popover-
    detection/

    View Slide

  48. Thank you!

    View Slide

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

    View Slide