ActionSheetPopoverPresenter.swift 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. //
  2. // ActionSheetPopoverPresenter.swift
  3. // Sheeeeeeeeet
  4. //
  5. // Created by Daniel Saidi on 2017-11-24.
  6. // Copyright © 2017 Daniel Saidi. All rights reserved.
  7. //
  8. /*
  9. This presenter will present action sheets as popovers, just
  10. as regular UIAlertControllers are displayed on the iPad. It
  11. should only be used when a sheet is displayed on an iPad.
  12. Since popovers have an arrow that should use the same color
  13. as the rest of the popover view, this presenter will remove
  14. any header view as well as combine items and buttons into a
  15. single section.
  16. */
  17. import UIKit
  18. open class ActionSheetPopoverPresenter: NSObject, ActionSheetPresenter {
  19. // MARK: - Initialization
  20. deinit { print("\(type(of: self)) deinit") }
  21. // MARK: - Properties
  22. open var availablePresentationSize: CGSize { return popover?.frameOfPresentedViewInContainerView.size ?? .zero }
  23. open var events = ActionSheetPresenterEvents()
  24. open var isDismissableWithTapOnBackground = true
  25. private var actionSheet: ActionSheet?
  26. private var actionSheetView: UIView?
  27. private var backgroundView: UIView?
  28. private weak var popover: UIPopoverPresentationController?
  29. // MARK: - ActionSheetPresenter
  30. public func dismiss(completion: @escaping () -> ()) {
  31. let dismissAction = { completion(); self.actionSheet = nil }
  32. let vc = actionSheet?.presentingViewController
  33. vc?.dismiss(animated: true) { dismissAction() } ?? dismissAction()
  34. }
  35. open func present(sheet: ActionSheet, in vc: UIViewController, from view: UIView?) {
  36. popover = self.popover(for: sheet, in: vc)
  37. popover?.sourceView = view
  38. popover?.sourceRect = view?.bounds ?? CGRect()
  39. popover?.delegate = self
  40. vc.present(sheet, animated: true, completion: nil)
  41. }
  42. open func present(sheet: ActionSheet, in vc: UIViewController, from item: UIBarButtonItem) {
  43. popover = self.popover(for: sheet, in: vc)
  44. popover?.barButtonItem = item
  45. vc.present(sheet, animated: true, completion: nil)
  46. }
  47. public func presentationFrame(for sheet: ActionSheet, in view: UIView) -> CGRect? {
  48. return nil
  49. }
  50. }
  51. // MARK: - UIPopoverPresentationControllerDelegate
  52. extension ActionSheetPopoverPresenter: UIPopoverPresentationControllerDelegate {
  53. public func popoverPresentationControllerShouldDismissPopover(_ controller: UIPopoverPresentationController) -> Bool {
  54. guard isDismissableWithTapOnBackground else { return false }
  55. events.didDismissWithBackgroundTap?()
  56. dismiss {}
  57. return false
  58. }
  59. }
  60. // MARK: - Private Functions
  61. private extension ActionSheetPopoverPresenter {
  62. func popover(for sheet: ActionSheet, in vc: UIViewController) -> UIPopoverPresentationController? {
  63. guard sheet.contentHeight > 0 else { return nil }
  64. setupSheetForPresentation(sheet)
  65. sheet.modalPresentationStyle = .popover
  66. let popover = sheet.popoverPresentationController
  67. popover?.backgroundColor = sheet.view.backgroundColor
  68. popover?.delegate = vc as? UIPopoverPresentationControllerDelegate
  69. return popover
  70. }
  71. func popoverItems(for sheet: ActionSheet) -> [ActionSheetItem] {
  72. let items: [ActionSheetItem] = sheet.items + sheet.buttons
  73. return items.filter { !($0 is ActionSheetCancelButton) }
  74. }
  75. func setupSheetForPresentation(_ sheet: ActionSheet) {
  76. self.actionSheet = sheet
  77. sheet.headerView = nil
  78. sheet.items = popoverItems(for: sheet)
  79. sheet.buttons = []
  80. sheet.preferredContentSize = sheet.preferredPopoverSize
  81. sheet.view.backgroundColor = sheet.itemsView.backgroundColor
  82. }
  83. }