14
14
15
15
@interface TOPasscodeViewController () <UIViewControllerTransitioningDelegate>
16
16
17
+ /* State */
18
+ @property (nonatomic , assign , readwrite ) TOPasscodeType passcodeType;
19
+ @property (nonatomic , assign ) CGFloat keyboardHeight;
20
+
21
+ /* Views */
17
22
@property (nonatomic , strong , readwrite ) UIVisualEffectView *backgroundEffectView;
18
23
@property (nonatomic , strong , readwrite ) UIView *backgroundView;
19
24
@property (nonatomic , strong , readwrite ) TOPasscodeView *passcodeView;
20
25
@property (nonatomic , strong , readwrite ) UIButton *biometricButton;
21
26
@property (nonatomic , strong , readwrite ) UIButton *cancelButton;
22
- @property (nonatomic , assign , readwrite ) TOPasscodeType passcodeType;
27
+
28
+
23
29
24
30
@end
25
31
@@ -47,6 +53,11 @@ - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibB
47
53
return self;
48
54
}
49
55
56
+ - (void )dealloc
57
+ {
58
+ [[NSNotificationCenter defaultCenter ] removeObserver: self name: UIKeyboardWillChangeFrameNotification object: nil ];
59
+ }
60
+
50
61
#pragma mark - View Setup -
51
62
52
63
- (void )setUp
@@ -61,6 +72,9 @@ - (void)setUp
61
72
else {
62
73
self.modalPresentationStyle = UIModalPresentationFullScreen;
63
74
}
75
+
76
+ [[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (keyboardWillChangeFrame: )
77
+ name: UIKeyboardWillChangeFrameNotification object: nil ];
64
78
}
65
79
66
80
- (void )setUpBackgroundEffectViewForStyle : (TOPasscodeViewStyle)style
@@ -199,13 +213,37 @@ - (void)viewDidLayoutSubviews
199
213
[self .passcodeView sizeToFitWidth: bounds.width];
200
214
201
215
// Re-center the pin view
202
- self.passcodeView .center = self.view .center ;
216
+ CGRect frame = self.passcodeView .frame ;
217
+ frame.origin .x = (bounds.width - frame.size .width ) * 0 .5f ;
218
+ frame.origin .y = ((bounds.height - self.keyboardHeight ) - frame.size .height ) * 0 .5f ;
219
+ self.passcodeView .frame = CGRectIntegral (frame);
203
220
}
204
221
205
222
- (void )viewWillAppear : (BOOL )animated
206
223
{
207
224
[super viewWillAppear: animated];
208
225
[self setNeedsStatusBarAppearanceUpdate ];
226
+
227
+ // Force an initial layout if the view hasn't been presented yet
228
+ [UIView performWithoutAnimation: ^{
229
+ [self .view setNeedsLayout ];
230
+ [self .view layoutIfNeeded ];
231
+ }];
232
+
233
+ // Show the keyboard if we're
234
+ if (self.passcodeType == TOPasscodeTypeCustomAlphanumeric) {
235
+ [self .passcodeView.inputField becomeFirstResponder ];
236
+ }
237
+ }
238
+
239
+ - (void )viewWillDisappear : (BOOL )animated
240
+ {
241
+ [super viewWillDisappear: animated];
242
+
243
+ // Dismiss the keyboard if it is visible
244
+ if (self.passcodeView .inputField .isFirstResponder ) {
245
+ [self .passcodeView.inputField resignFirstResponder ];
246
+ }
209
247
}
210
248
211
249
- (UIStatusBarStyle)preferredStatusBarStyle
@@ -331,6 +369,35 @@ - (void)didCompleteEnteringPasscode:(NSString *)passcode
331
369
}
332
370
}
333
371
372
+ #pragma mark - Keyboard Handling -
373
+ - (void )keyboardWillChangeFrame : (NSNotification *)notification
374
+ {
375
+ // Extract the keyboard information we need from the notification
376
+ CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue ];
377
+ CGFloat animationDuration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue ];
378
+ UIViewAnimationOptions animationCurve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue ];
379
+
380
+ // Work out the on-screen height of the keyboard
381
+ self.keyboardHeight = self.view .bounds .size .height - keyboardFrame.origin .y ;
382
+ self.keyboardHeight = MAX (self.keyboardHeight , 0 .0f );
383
+
384
+ // Set that the view needs to be laid out
385
+ [self .view setNeedsLayout ];
386
+
387
+ if (animationDuration < FLT_EPSILON) {
388
+ return ;
389
+ }
390
+
391
+ // Animate the content sliding up and down with the keyboard
392
+ [UIView animateWithDuration: animationDuration
393
+ delay: 0 .0f
394
+ // usingSpringWithDamping:1.0f
395
+ // initialSpringVelocity:1.0f
396
+ options: animationCurve
397
+ animations: ^{ [self .view layoutIfNeeded ]; }
398
+ completion: nil ];
399
+ }
400
+
334
401
#pragma mark - Transitioning Delegate -
335
402
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController : (UIViewController *)presented
336
403
presentingController : (UIViewController *)presenting
0 commit comments