@@ -146,29 +146,22 @@ public final class KeyboardObserver {
146
146
147
147
/// How the keyboard overlaps the view provided. If the view is not on screen (eg, no window),
148
148
/// or the observer has not yet learned about the keyboard's position, this method returns nil.
149
- public func currentFrame( in view : UIView ) -> KeyboardFrame ? {
149
+ func currentFrame( in view: UIView ) -> KeyboardFrame ? {
150
150
151
- guard view . window != nil else {
151
+ guard let window = view . window else {
152
152
return nil
153
153
}
154
154
155
155
guard let notification = latestNotification else {
156
156
return nil
157
157
}
158
158
159
- let frame : CGRect
159
+ let screen = notification . screen ?? window . screen
160
160
161
- if #available( iOS 16 . 1 , * ) {
162
- frame = notification. screen. coordinateSpace. convert (
163
- notification. endingFrame,
164
- to: view
165
- )
166
- } else {
167
- frame = view. convert (
168
- notification. endingFrame,
169
- from: nil
170
- )
171
- }
161
+ let frame = screen. coordinateSpace. convert (
162
+ notification. endingFrame,
163
+ to: view
164
+ )
172
165
173
166
if frame. intersects ( view. bounds) {
174
167
return . overlapping( frame: frame)
@@ -225,23 +218,19 @@ extension KeyboardObserver {
225
218
var animationDuration : Double = 0.0
226
219
var animationCurve : UIView . AnimationCurve = . easeInOut
227
220
228
- @available ( iOS 16 . 1 , * )
229
- var screen : UIScreen {
230
- get {
231
- guard let screen = _screen else {
232
- fatalError ( " UIScreen value was not initialized from notification object. " )
233
- }
234
- return screen
235
- }
236
- set {
237
- _screen = newValue
238
- }
239
- }
240
-
241
- // Note: Using this to work around: "Stored properties cannot be marked
242
- // potentially unavailable with '@available'"
243
- // Can be removed when deployment target is >= 16.1. @available(iOS 16.1, *)
244
- private var _screen : UIScreen ?
221
+ /// The `UIScreen` that the keyboard appears on.
222
+ ///
223
+ /// This may influence the `KeyboardFrame` calculation when the app is not in full screen,
224
+ /// such as in Split View, Slide Over, and Stage Manager.
225
+ ///
226
+ /// - note: In iOS 16.1 and later, every `keyboardWillChangeFrameNotification` and
227
+ /// `keyboardDidChangeFrameNotification` is _supposed_ to include a `UIScreen`
228
+ /// in a the notification, however we've had reports that this isn't always the case (at least when
229
+ /// using the iOS 16.1 simulator runtime). If a screen is _not_ included in an iOS 16.1+ notification,
230
+ /// we do not throw a `ParseError` as it would cause the entire notification to be discarded.
231
+ ///
232
+ /// [Apple Documentation](https://developer.apple.com/documentation/uikit/uiresponder/1621623-keyboardwillchangeframenotificat)
233
+ var screen : UIScreen ?
245
234
246
235
init ( with notification: Notification ) throws {
247
236
@@ -269,14 +258,7 @@ extension KeyboardObserver {
269
258
270
259
self . animationCurve = animationCurve
271
260
272
- if #available( iOS 16 . 1 , * ) {
273
- guard let screen = notification. object as? UIScreen else {
274
- throw ParseError . missingScreen
275
- }
276
-
277
- self . screen = screen
278
- }
279
-
261
+ screen = notification. object as? UIScreen
280
262
}
281
263
282
264
enum ParseError : Error , Equatable {
@@ -285,7 +267,6 @@ extension KeyboardObserver {
285
267
case missingEndingFrame
286
268
case missingAnimationDuration
287
269
case missingAnimationCurve
288
- case missingScreen
289
270
}
290
271
}
291
272
}
0 commit comments