How to dismiss an UIAlertController and the keyboard simultaneously?

后端 未结 8 1238
离开以前
离开以前 2021-02-05 13:04

I have created a signup form with a UIAlertController and used the method addTextFieldWithConfigurationHandler to add a text field. But there is a litt

8条回答
  •  夕颜
    夕颜 (楼主)
    2021-02-05 13:24

    You can set your view controller or other object as transitioning delegate of your UIAlertController (alert.transitioningDelegate) and make a custom animation for dismissing. Code sample:

    @interface ViewController () 
    @property (assign, nonatomic) NSTimeInterval keyboardAnimationDuration;
    @property (assign, nonatomic) CGFloat keyboardHeight;
    @property (nonatomic, strong) UIAlertController *alertController;
    @property (nonatomic,strong) id  transitioningDelegateForAlertController;
    @end
    
    @implementation ViewController
    
    - (void)dealloc {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self subscribeForKeyboardNotification];
    }
    
    #pragma mark - Keyboard notifications
    
    - (void)subscribeForKeyboardNotification {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillAppear:)
                                                     name:UIKeyboardWillShowNotification
                                                   object:nil];
    }
    
    - (void)keyboardWillAppear:(NSNotification *)notification {
        self.keyboardAnimationDuration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        self.keyboardHeight = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
    }
    
    #pragma mark - IBAction
    
    - (IBAction)showAlertButtonPressed:(id)sender {
        [self showAlert];
    }
    
    - (void)showAlert {
        self.alertController = [UIAlertController alertControllerWithTitle:@"Alert"
                                                                                 message:@"This is a demo alert"
                                                                          preferredStyle:UIAlertControllerStyleAlert];
        __weak typeof(self) weakSelf = self;
        [self.alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
            textField.delegate = weakSelf;
        }];
        self.transitioningDelegateForAlertController = self.alertController.transitioningDelegate;
        self.alertController.transitioningDelegate = self;
        [self.alertController addAction:[UIAlertAction actionWithTitle:@"Ok"
                                                            style:UIAlertActionStyleCancel
                                                          handler:nil]];
        [self presentViewController:self.alertController animated:YES completion:nil];
    }
    
    #pragma mark - UITextFieldDelegate
    
    - (BOOL)textFieldShouldReturn:(UITextField *)textField {
        [self.alertController dismissViewControllerAnimated:YES completion:nil];
        return YES;
    }
    
    #pragma mark - UIViewControllerTransitioningDelegate
    
    - (id )animationControllerForPresentedController:(UIViewController *)presented
                                                                       presentingController:(UIViewController *)presenting
                                                                           sourceController:(UIViewController *)source {
        return [self.transitioningDelegateForAlertController animationControllerForPresentedController:presented
                                                                              presentingController:presenting
                                                                                  sourceController:source];
    }
    
    - (id )animationControllerForDismissedController:(UIViewController *)dismissed {
        return self;
    }
    
    #pragma mark - UIViewControllerAnimatedTransitioning
    
    - (NSTimeInterval)transitionDuration:(id )transitionContext {
        return self.keyboardAnimationDuration ?: 0.5;
    }
    
    - (void)animateTransition:(id )transitionContext {
        UIViewController *destination = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        if ([destination isBeingPresented])
            [self animatePresentation:transitionContext];
        else
            [self animateDismissal:transitionContext];
    }
    
    - (void)animatePresentation:(id )transitionContext {
        NSTimeInterval transitionDuration = [self transitionDuration:transitionContext];
        UIViewController *fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        UIView *container = transitionContext.containerView;
        fromController.view.frame = container.bounds;
        toController.view.frame = container.bounds;
        toController.view.alpha = 0.0f;
        [container addSubview:toController.view];
        [fromController beginAppearanceTransition:NO animated:YES];
        [UIView animateWithDuration:transitionDuration
                         animations:^{
                             toController.view.alpha = 1.0;
                         }
                         completion:^(BOOL finished) {
                             [fromController endAppearanceTransition];
                             [transitionContext completeTransition:YES];
                         }];
    }
    
    - (void)animateDismissal:(id )transitionContext {
        NSTimeInterval transitionDuration = [self transitionDuration:transitionContext];
        UIViewController *fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        [toController beginAppearanceTransition:YES animated:YES];
        [UIView animateWithDuration:transitionDuration
                         animations:^{
                             fromController.view.alpha = 0.0;
                             [fromController.view endEditing:YES];
                             CGRect frame = fromController.view.frame;
                             frame.origin.y += self.keyboardHeight / 2;
                             fromController.view.frame = frame;
                         }
                         completion:^(BOOL finished) {
                             [toController endAppearanceTransition];
                             [transitionContext completeTransition:YES];
                         }];
    }
    
    @end
    

    Result:

    enter image description here

    P.S.: I used old alert's transitioning delegate for presentation because I can't reproduce an original animation. So animatePresentation: method is never used.

提交回复
热议问题