Skip to content

Commit f6db0cb

Browse files
committed
Add a .animate() API that supports UIKit animations.
1 parent 7e36910 commit f6db0cb

File tree

1 file changed

+202
-0
lines changed

1 file changed

+202
-0
lines changed
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
#if canImport(UIKit)
2+
import UIKit
3+
import ReactiveSwift
4+
5+
extension Scheduler {
6+
/// Wraps scheduled actions in `UIView.animate`.
7+
///
8+
/// - Parameter duration: The `duration` parameter passed to `UIView.animate`.
9+
/// - Parameter delay: The `delay` parameter passed to `UIView.animate`.
10+
/// - Parameter animationOptions: The `options` parameter passed to `UIView.animate`
11+
/// - Returns: A scheduler that wraps scheduled actions in `UIView.animate`.
12+
public func animate(
13+
withDuration duration: TimeInterval,
14+
delay: TimeInterval = 0,
15+
options animationOptions: UIView.AnimationOptions = []
16+
) -> Scheduler {
17+
UIKitAnimationScheduler(
18+
scheduler: self,
19+
params: .init(
20+
duration: duration,
21+
delay: delay,
22+
options: animationOptions,
23+
mode: .normal
24+
)
25+
)
26+
}
27+
28+
/// Wraps scheduled actions in `UIView.animate`.
29+
///
30+
/// - Parameter duration: The `duration` parameter passed to `UIView.animate`.
31+
/// - Parameter delay: The `delay` parameter passed to `UIView.animate`.
32+
/// - Parameter dampingRatio: The `dampingRatio` parameter passed to `UIView.animate`
33+
/// - Parameter velocity: The `velocity` parameter passed to `UIView.animate`
34+
/// - Parameter animationOptions: The `options` parameter passed to `UIView.animate`
35+
/// - Returns: A scheduler that wraps scheduled actions in `UIView.animate`.
36+
public func animate(
37+
withDuration duration: TimeInterval,
38+
delay: TimeInterval = 0,
39+
usingSpringWithDamping dampingRatio: CGFloat,
40+
initialSpringVelocity velocity: CGFloat,
41+
options animationOptions: UIView.AnimationOptions
42+
) -> Scheduler {
43+
UIKitAnimationScheduler(
44+
scheduler: self,
45+
params: .init(
46+
duration: duration,
47+
delay: delay,
48+
options: animationOptions,
49+
mode: .spring(dampingRatio: dampingRatio, velocity: velocity)
50+
)
51+
)
52+
}
53+
}
54+
55+
extension DateScheduler {
56+
/// Wraps scheduled actions in `UIView.animate`.
57+
///
58+
/// - Parameter duration: The `duration` parameter passed to `UIView.animate`.
59+
/// - Parameter delay: The `delay` parameter passed to `UIView.animate`.
60+
/// - Parameter animationOptions: The `options` parameter passed to `UIView.animate`
61+
/// - Returns: A scheduler that wraps scheduled actions in `UIView.animate`.
62+
public func animate(
63+
withDuration duration: TimeInterval,
64+
delay: TimeInterval = 0,
65+
options animationOptions: UIView.AnimationOptions = []
66+
) -> DateScheduler {
67+
UIKitAnimationDateScheduler(
68+
scheduler: self,
69+
params: .init(
70+
duration: duration,
71+
delay: delay,
72+
options: animationOptions,
73+
mode: .normal
74+
)
75+
)
76+
}
77+
78+
/// Wraps scheduled actions in `UIView.animate`.
79+
///
80+
/// - Parameter duration: The `duration` parameter passed to `UIView.animate`.
81+
/// - Parameter delay: The `delay` parameter passed to `UIView.animate`.
82+
/// - Parameter dampingRatio: The `dampingRatio` parameter passed to `UIView.animate`
83+
/// - Parameter velocity: The `velocity` parameter passed to `UIView.animate`
84+
/// - Parameter animationOptions: The `options` parameter passed to `UIView.animate`
85+
/// - Returns: A scheduler that wraps scheduled actions in `UIView.animate`.
86+
public func animate(
87+
withDuration duration: TimeInterval,
88+
delay: TimeInterval = 0,
89+
usingSpringWithDamping dampingRatio: CGFloat,
90+
initialSpringVelocity velocity: CGFloat,
91+
options animationOptions: UIView.AnimationOptions
92+
) -> DateScheduler {
93+
UIKitAnimationDateScheduler(
94+
scheduler: self,
95+
params: .init(
96+
duration: duration,
97+
delay: delay,
98+
options: animationOptions,
99+
mode: .spring(dampingRatio: dampingRatio, velocity: velocity)
100+
)
101+
)
102+
}
103+
}
104+
105+
private struct AnimationParams {
106+
let duration: TimeInterval
107+
let delay: TimeInterval
108+
let options: UIView.AnimationOptions
109+
let mode: Mode
110+
111+
enum Mode {
112+
case normal
113+
case spring(dampingRatio: CGFloat, velocity: CGFloat)
114+
}
115+
}
116+
117+
public final class UIKitAnimationScheduler: Scheduler {
118+
private let scheduler: Scheduler
119+
private let params: AnimationParams
120+
121+
fileprivate init(scheduler: Scheduler, params: AnimationParams) {
122+
self.scheduler = scheduler
123+
self.params = params
124+
}
125+
126+
public func schedule(_ action: @escaping () -> Void) -> Disposable? {
127+
scheduler.schedule { [params = self.params] in
128+
switch params.mode {
129+
case .normal:
130+
UIView.animate(
131+
withDuration: params.duration,
132+
delay: params.duration,
133+
options: params.options,
134+
animations: action
135+
)
136+
case let .spring(dampingRatio, velocity):
137+
UIView.animate(
138+
withDuration: params.duration,
139+
delay: params.delay,
140+
usingSpringWithDamping: dampingRatio,
141+
initialSpringVelocity: velocity,
142+
options: params.options,
143+
animations: action
144+
)
145+
}
146+
}
147+
}
148+
}
149+
150+
public final class UIKitAnimationDateScheduler: DateScheduler {
151+
public var currentDate: Date {
152+
scheduler.currentDate
153+
}
154+
155+
private let scheduler: DateScheduler
156+
private let params: AnimationParams
157+
158+
fileprivate init(scheduler: DateScheduler, params: AnimationParams) {
159+
self.scheduler = scheduler
160+
self.params = params
161+
}
162+
163+
private func animatedAction(_ action: @escaping () -> Void) -> () -> Void {
164+
{ [params = self.params] in
165+
switch params.mode {
166+
case .normal:
167+
UIView.animate(
168+
withDuration: params.duration,
169+
delay: params.duration,
170+
options: params.options,
171+
animations: action
172+
)
173+
case let .spring(dampingRatio, velocity):
174+
UIView.animate(
175+
withDuration: params.duration,
176+
delay: params.delay,
177+
usingSpringWithDamping: dampingRatio,
178+
initialSpringVelocity: velocity,
179+
options: params.options,
180+
animations: action
181+
)
182+
}
183+
}
184+
}
185+
186+
public func schedule(_ action: @escaping () -> Void) -> Disposable? {
187+
scheduler.schedule(animatedAction(action))
188+
}
189+
190+
public func schedule(after date: Date, action: @escaping () -> Void) -> Disposable? {
191+
scheduler.schedule(after: date, action: animatedAction(action))
192+
}
193+
194+
public func schedule(
195+
after date: Date, interval: DispatchTimeInterval, leeway: DispatchTimeInterval,
196+
action: @escaping () -> Void
197+
) -> Disposable? {
198+
scheduler.schedule(after: date, interval: interval, leeway: leeway, action: animatedAction(action))
199+
}
200+
}
201+
202+
#endif

0 commit comments

Comments
 (0)