/
ActionSheetStandardPresenter.swift
166 lines (125 loc) · 5.04 KB
/
ActionSheetStandardPresenter.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//
// ActionSheetStandardPresenter.swift
// Sheeeeeeeeet
//
// Created by Daniel Saidi on 2017-11-27.
// Copyright © 2017 Daniel Saidi. All rights reserved.
//
/*
This presenter presents action sheets as regular iOS action
sheets, which are presented with a slide-in from the bottom
of the screen.
The `presentationStyle` property will affect how the action
sheet is presented. The default `keyWindow` option uses the
entire application window and will present the action sheet
in full screen. The `currentContext` option uses the source
view controller's view bounds instead.
*/
import UIKit
open class ActionSheetStandardPresenter: ActionSheetPresenter {
// MARK: - Initialization
public init() {}
// MARK: - Properties
public var events = ActionSheetPresenterEvents()
public var isDismissableWithTapOnBackground = true
public var presentationStyle = PresentationStyle.currentContext
var actionSheet: ActionSheet?
var animationDelay: TimeInterval = 0
var animationDuration: TimeInterval = 0.3
// MARK: - Types
public enum PresentationStyle {
case keyWindow, currentContext
}
// MARK: - ActionSheetPresenter
open func dismiss(completion: @escaping () -> ()) {
completion()
removeBackgroundView()
removeActionSheet {
self.actionSheet?.view.removeFromSuperview()
self.actionSheet = nil
}
}
open func present(sheet: ActionSheet, in vc: UIViewController, from view: UIView?, completion: @escaping () -> ()) {
present(sheet: sheet, in: vc, completion: completion)
}
open func present(sheet: ActionSheet, in vc: UIViewController, from item: UIBarButtonItem, completion: @escaping () -> ()) {
present(sheet: sheet, in: vc, completion: completion)
}
open func present(sheet: ActionSheet, in vc: UIViewController, completion: @escaping () -> ()) {
actionSheet = sheet
addActionSheet(sheet, to: vc)
addBackgroundViewTapAction(to: sheet.backgroundView)
presentBackgroundView()
presentActionSheet(completion: completion)
}
open func refreshActionSheet() {
guard let sheet = actionSheet else { return }
sheet.topMargin?.constant = sheet.margin(at: .top)
sheet.leftMargin?.constant = sheet.margin(at: .left)
sheet.rightMargin?.constant = sheet.margin(at: .right)
sheet.bottomMargin?.constant = sheet.margin(at: .bottom)
}
// MARK: - Protected Functions
open func addBackgroundViewTapAction(to view: UIView?) {
view?.isUserInteractionEnabled = true
let action = #selector(backgroundViewTapAction)
let tap = UITapGestureRecognizer(target: self, action: action)
view?.addGestureRecognizer(tap)
}
open func animate(_ animation: @escaping () -> ()) {
animate(animation, completion: nil)
}
open func animate(_ animation: @escaping () -> (), completion: (() -> ())?) {
guard animationDuration >= 0 else { return }
UIView.animate(
withDuration: animationDuration,
delay: animationDelay,
options: [.curveEaseOut],
animations: animation) { _ in completion?() }
}
open func presentActionSheet(completion: @escaping () -> ()) {
guard let view = actionSheet?.stackView else { return }
let frame = view.frame
view.frame.origin.y += frame.height + 100
let animation = { view.frame = frame }
animate(animation, completion: completion)
}
open func presentBackgroundView() {
guard let view = actionSheet?.backgroundView else { return }
view.alpha = 0
let animation = { view.alpha = 1 }
animate(animation)
}
open func removeActionSheet(completion: @escaping () -> ()) {
guard let view = actionSheet?.stackView else { return }
let animation = { view.frame.origin.y += view.frame.height + 100 }
animate(animation) { completion() }
}
open func removeBackgroundView() {
guard let view = actionSheet?.backgroundView else { return }
let animation = { view.alpha = 0 }
animate(animation)
}
}
// MARK: - Internal Functions
extension ActionSheetStandardPresenter {
func addActionSheetToKeyWindow(_ sheet: ActionSheet) {
let window = UIApplication.shared.keyWindow
sheet.view.frame = window?.bounds ?? .zero
window?.addSubview(sheet.view)
}
func addActionSheet(_ sheet: ActionSheet, to vc: UIViewController) {
if presentationStyle == .keyWindow { return addActionSheetToKeyWindow(sheet) }
let view = vc.view
sheet.view.frame = view?.bounds ?? .zero
view?.addSubview(sheet.view)
}
}
// MARK: - Actions
@objc public extension ActionSheetStandardPresenter {
func backgroundViewTapAction() {
guard isDismissableWithTapOnBackground else { return }
events.didDismissWithBackgroundTap?()
dismiss {}
}
}