@@ -18,14 +18,10 @@ public class RNSSplitViewScreenController: UIViewController {
18
18
return splitViewScreenComponentView. reactEventEmitter ( )
19
19
}
20
20
21
- private var displayLink : CADisplayLink ?
22
- private var lastAnimationFrame : CGRect ?
23
- private var transitionInProgress : Bool
21
+ private var viewSizeTransitionState : ViewSizeTransitionState ? = nil
24
22
25
23
@objc public required init ( splitViewScreenComponentView: RNSSplitViewScreenComponentView ) {
26
24
self . splitViewScreenComponentView = splitViewScreenComponentView
27
- self . transitionInProgress = false
28
-
29
25
super. init ( nibName: nil , bundle: nil )
30
26
}
31
27
@@ -74,8 +70,8 @@ public class RNSSplitViewScreenController: UIViewController {
74
70
/// @return true if the transition is running, false otherwise.
75
71
///
76
72
@objc
77
- public func isTransitionInProgress ( ) -> Bool {
78
- return transitionInProgress
73
+ public func isViewSizeTransitionInProgress ( ) -> Bool {
74
+ return viewSizeTransitionState != nil
79
75
}
80
76
81
77
// MARK: Signals
@@ -97,33 +93,31 @@ public class RNSSplitViewScreenController: UIViewController {
97
93
) {
98
94
super. viewWillTransition ( to: size, with: coordinator)
99
95
100
- transitionInProgress = true
96
+ viewSizeTransitionState = ViewSizeTransitionState ( )
101
97
102
98
coordinator. animate (
103
99
alongsideTransition: { [ weak self] context in
104
100
guard let self = self else { return }
105
- if self . displayLink == nil {
106
- self . displayLink = CADisplayLink (
107
- target: self , selector: #selector( trackTransitionProgress) )
108
- self . displayLink? . add ( to: . main, forMode: . common)
101
+ guard let viewSizeTransitionState = self . viewSizeTransitionState else { return }
102
+
103
+ if viewSizeTransitionState. displayLink == nil {
104
+ viewSizeTransitionState. setupDisplayLink (
105
+ forTarget: self , selector: #selector( trackTransitionProgress) )
109
106
}
110
107
} ,
111
108
completion: { [ weak self] context in
112
109
guard let self = self else { return }
113
- self . stopAnimation ( )
110
+ self . cleanupViewSizeTransitionState ( )
114
111
// After the animation completion, ensure that ShadowTree state
115
112
// is calculated relatively to the ancestor's frame by requesting
116
113
// the state update.
117
114
self . updateShadowTreeState ( )
118
115
} )
119
116
}
120
117
121
- private func stopAnimation( ) {
122
- lastAnimationFrame = nil
123
- transitionInProgress = false
124
-
125
- displayLink? . invalidate ( )
126
- displayLink = nil
118
+ private func cleanupViewSizeTransitionState( ) {
119
+ viewSizeTransitionState? . invalidate ( )
120
+ viewSizeTransitionState = nil
127
121
}
128
122
129
123
///
@@ -133,7 +127,7 @@ public class RNSSplitViewScreenController: UIViewController {
133
127
@objc
134
128
private func trackTransitionProgress( ) {
135
129
if let currentFrame = view. layer. presentation ( ) ? . frame {
136
- lastAnimationFrame = currentFrame
130
+ viewSizeTransitionState ? . lastViewPresentationFrame = currentFrame
137
131
updateShadowTreeState ( )
138
132
}
139
133
}
@@ -172,11 +166,12 @@ public class RNSSplitViewScreenController: UIViewController {
172
166
// If the resize animation is currently running, we prefer to apply dynamic updates,
173
167
// based on the results from the presentation layer
174
168
// which is read from `trackTransitionProgress` method.
175
- if let currentSize = lastAnimationFrame? . size {
176
- applyTransitioningShadowState (
177
- size: currentSize,
178
- ancestorView: ancestorView!
179
- )
169
+ if let lastViewPresentationFrame = viewSizeTransitionState? . lastViewPresentationFrame,
170
+ !lastViewPresentationFrame. isNull
171
+ {
172
+ shadowStateProxy. updateShadowState (
173
+ ofComponent: splitViewScreenComponentView, withFrame: lastViewPresentationFrame,
174
+ inContextOfAncestorView: ancestorView!)
180
175
return
181
176
}
182
177
@@ -186,27 +181,12 @@ public class RNSSplitViewScreenController: UIViewController {
186
181
// to prevent interrupting with the frames that are less important for us.
187
182
// This works fine, because after the animation completion, we're sending the last update
188
183
// which is compatible with the frame which would be calculated relatively to the ancestor here.
189
- if !isTransitionInProgress( ) {
190
- applyStaticShadowStateRelativeToAncestor ( ancestorView!)
184
+ if !isViewSizeTransitionInProgress( ) {
185
+ shadowStateProxy. updateShadowState (
186
+ ofComponent: splitViewScreenComponentView, inContextOfAncestorView: ancestorView)
191
187
}
192
188
}
193
189
194
- private func applyTransitioningShadowState( size: CGSize , ancestorView: UIView ) {
195
- let localOrigin = splitViewScreenComponentView. convert (
196
- splitViewScreenComponentView. frame. origin,
197
- to: ancestorView
198
- )
199
- let convertedFrame = CGRect ( origin: localOrigin, size: size)
200
- shadowStateProxy. updateShadowState ( withFrame: convertedFrame)
201
- }
202
-
203
- private func applyStaticShadowStateRelativeToAncestor( _ ancestorView: UIView ) {
204
- shadowStateProxy. updateShadowState (
205
- ofComponent: splitViewScreenComponentView,
206
- inContextOfAncestorView: ancestorView
207
- )
208
- }
209
-
210
190
///
211
191
/// @brief Request ShadowNode state update when the SplitView screen frame origin has changed.
212
192
///
@@ -220,7 +200,7 @@ public class RNSSplitViewScreenController: UIViewController {
220
200
// During the transition, we're listening for the animation
221
201
// frame updates on the presentation layer and we're
222
202
// treating these updates as the source of truth
223
- if !isTransitionInProgress ( ) {
203
+ if !isViewSizeTransitionInProgress ( ) {
224
204
shadowStateProxy. updateShadowState (
225
205
ofComponent: splitViewScreenComponentView, inContextOfAncestorView: splitViewController. view
226
206
)
@@ -245,3 +225,23 @@ public class RNSSplitViewScreenController: UIViewController {
245
225
reactEventEmitter. emitOnDidDisappear ( )
246
226
}
247
227
}
228
+
229
+ private class ViewSizeTransitionState {
230
+ public var displayLink : CADisplayLink ?
231
+ public var lastViewPresentationFrame : CGRect = CGRect . null
232
+
233
+ public func setupDisplayLink( forTarget target: Any , selector sel: Selector ) {
234
+ if displayLink != nil {
235
+ displayLink? . invalidate ( )
236
+ }
237
+
238
+ displayLink = CADisplayLink ( target: target, selector: sel)
239
+ displayLink!. add ( to: . main, forMode: . common)
240
+ }
241
+
242
+ public func invalidate( ) {
243
+ displayLink? . invalidate ( )
244
+ displayLink = nil
245
+ lastViewPresentationFrame = CGRect . null
246
+ }
247
+ }
0 commit comments