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 full-size slide

  2. VIEW CONTROLLERS
    EVERYWHERE

    View full-size slide

  3. PRESENTATION CONTROLLERS
    EVERYWHERE

    View full-size slide

  4. PRESENTATION
    VS.
    TRANSITION

    View full-size slide

  5. What's the difference?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  9. PRESENTATION
    UIPresentationController
    iOS 8+

    View full-size slide

  10. UIPresentationController
    WAT?

    View full-size slide

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

    View full-size slide

  12. UNDERSTANDING
    THE PRESENTATION API

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. Special
    PRESENTATIONS

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  23. The API is easy to misuse.

    View full-size slide

  24. #SORRYNOTSORRY

    View full-size slide

  25. HOW TO USE
    CUSTOM PRESENTATION
    CONTROLLERS

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  30. 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 full-size slide

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

    View full-size slide

  32. BETTER THAN VIEW
    CONTROLLER CONTAINMENT

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  35. enum NavigationStyle {
    case None
    case WithNavigation
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  38. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide