如何同时解除UIAlertController和键盘?

时间:2014-10-02 13:20:38

标签: ios ios8 uialertcontroller

我创建了一个包含UIAlertController的注册表单,并使用方法addTextFieldWithConfigurationHandler添加了一个文本字段。但是有一点问题。

当表单出现时,键盘和模态会以平滑的动画显示。关闭表单时,模式将首先消失 ,然后然后键盘消失。这使键盘突然下降。

如何让模态和键盘优雅地消失?

lazy var alertController: UIAlertController = { [weak self] in
    let alert = UIAlertController(title: "Alert", message: "This is a demo alert", preferredStyle: .Alert)
    alert.addTextFieldWithConfigurationHandler { textField in
        textField.delegate = self
    }
    alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
    return alert
}()

@IBAction func alert() {
    presentViewController(alertController, animated: true, completion: nil)
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
    alertController.dismissViewControllerAnimated(true, completion: nil)
    return true
}

presenting and dismissing

8 个答案:

答案 0 :(得分:15)

您可以将视图控制器或其他对象设置为UIAlertController(alert.transitioningDelegate)的转换委托,并制作用于解除的自定义动画。 代码示例:

@interface ViewController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning, UITextFieldDelegate>
@property (assign, nonatomic) NSTimeInterval keyboardAnimationDuration;
@property (assign, nonatomic) CGFloat keyboardHeight;
@property (nonatomic, strong) UIAlertController *alertController;
@property (nonatomic,strong) id <UIViewControllerTransitioningDelegate> 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 <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
                                                                   presentingController:(UIViewController *)presenting
                                                                       sourceController:(UIViewController *)source {
    return [self.transitioningDelegateForAlertController animationControllerForPresentedController:presented
                                                                          presentingController:presenting
                                                                              sourceController:source];
}

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    return self;
}

#pragma mark - UIViewControllerAnimatedTransitioning

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
    return self.keyboardAnimationDuration ?: 0.5;
}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    UIViewController *destination = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    if ([destination isBeingPresented])
        [self animatePresentation:transitionContext];
    else
        [self animateDismissal:transitionContext];
}

- (void)animatePresentation:(id <UIViewControllerContextTransitioning>)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 <UIViewControllerContextTransitioning>)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

结果:

enter image description here

P.S。:我使用旧警报过渡代表进行演示,因为我无法复制原始动画。因此永远不会使用animatePresentation:方法。

答案 1 :(得分:9)

我遇到了完全相同的问题并偶然找到了解决方案。你可能不再需要这个,但为了像我这样的其他人,这就是答案:

夫特:

override func canBecomeFirstResponder() -> Bool {
    return true
}

目标-C:

- (BOOL)canBecomeFirstResponder {
    return true;
}

只需在处理警报的视图控制器中添加此代码即可。仅在swift中测试过。

答案 2 :(得分:2)

非常简单。

如果您的UIAlertController代表出现在自我 View Controller中。那么你可以在它的Dismiss AlertController的委托方法中做到这一点。您可以在UIAlertController对象中[youtTextField resignFirstResponder],它有一个用于关闭它的按钮。 (例如“确定”或“取消”)因此您所呈现的KeyBoard将被解雇。

我没有尝试过,但它会起作用。但你必须正确处理textField和Alert。

答案 3 :(得分:1)

我认为UIAlertController的跳跃是在你按下键盘上的'return'后它解散了。如果是这样,我找到了一种让Alert和键盘顺利解除返回动作的方法。

您需要在类文件

中声明UIAlertController
@property (strong, nonatomic) UIAlertController *alertController;

您还需要将UITextFieldDelegate与viewController一起使用 将textField添加到UIAlertController时,您需要将其委托给self。 (weakSelf使用,因为它在一个区块内)

@interface ViewController ()<UITextFieldDelegate>

在拍卖UIAlertController的方法中 -

   self.alertController = [UIAlertController alertControllerWithTitle:@"Alert" message:@"This is the message" preferredStyle:UIAlertControllerStyleAlert];


   __weak typeof(self) weakSelf = self;

   [self.alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
       textField.delegate = weakSelf;
   }];

   [self presentViewController:self.alertController animated:YES completion:nil];

添加此UITextField委托方法,该方法将在键盘上按下返回按钮后触发。这意味着您可以在键盘解除之前对UIAlertController进行操作,从而使其完全正常工作。

-(BOOL)textFieldShouldReturn:(UITextField *)textField{

   [self.alertController dismissViewControllerAnimated:YES completion:nil];

   return YES;

}

我已经对此进行了测试,并且应该按照您的要求运行。

谢谢, 吉姆

答案 4 :(得分:0)

   - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

   { 
       [self.view endEditing:YES];
      // or you can write [yourtextfield refignFirstResponder]
       [alertView dismissWithClickedButtonIndex:buttonIndex animated:TRUE];
   }

答案 5 :(得分:0)

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

   { 

if (buttonIndex==1) {

        [[alertView textFieldAtIndex:0] resignFirstResponder];

        } else {

            [[alertView textFieldAtIndex:0] resignFirstResponder];

        }
    }

使用您的按钮索引(确定或取消按钮索引)

答案 6 :(得分:0)

不需要做任何事情你只需要实现这么多代码,它对我有用,不需要声明任何类型的委托方法

- (void)showAlert {
self.alertController = [UIAlertController alertControllerWithTitle:@"Alert"
                                                           message:@"Enter Name:"
                                                    preferredStyle:UIAlertControllerStyleAlert];
[self.alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {

}];
[self.alertController addAction:[UIAlertAction actionWithTitle:@"Ok"
                                                         style:UIAlertActionStyleCancel
                                                       handler:nil]];
[self presentViewController:self.alertController animated:YES completion:nil];

}

答案 7 :(得分:0)

用于UIAlertController的Swizzle viewWillDisappear方法,并在correspodent文本字段上执行resignFirstResponder或在控制器的视图上调用endEditing:

我正在使用这个ReactiveCocoa:

        let alert = UIAlertController(title: "", message: "", preferredStyle: .Alert)

        alert.addTextFieldWithConfigurationHandler {
           textField in
        }

        let textField = alert.textFields!.first!

        alert.rac_signalForSelector(#selector(viewWillDisappear(_:)))
             .subscribeNext {
                 _ in
                 textField.resignFirstResponder()
             }