如何同时关闭 UIAlertController 和键盘?

Posted

技术标签:

【中文标题】如何同时关闭 UIAlertController 和键盘?【英文标题】:How to dismiss an UIAlertController and the keyboard simultaneously? 【发布时间】:2014-10-02 13:20:37 【问题描述】:

我创建了一个带有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

【问题讨论】:

您能否发布您用于创建 UIAlertController 和操作的代码。谢谢 如果您可以分享一个测试应用程序,我愿意为您检查。 【参考方案1】:

您可以将您的视图控制器或其他对象设置为您的 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

结果:

P.S.:我使用旧警报的过渡委托进行演示,因为我无法重现原始动画。所以animatePresentation: 方法永远不会被使用。

【讨论】:

真的很有启发性,谢谢。能否请您发布您的想法的示例代码? 请试试我回答中的代码,告诉我你期待什么样的动画。 我很期待警报消失时键盘同时消失的动画,就像它们一起出现一样。【参考方案2】:

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

斯威夫特:

override func canBecomeFirstResponder() -> Bool 
    return true

目标-C:

- (BOOL)canBecomeFirstResponder 
    return true;

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

【讨论】:

【参考方案3】:

其实很简单。

如果您的 UIAlertController 委托存在于 self 视图控制器中。那么你可以在 Dismiss AlertController 的委托方法中执行此操作。你可以在你的 UIAlertController 对象中 [youtTextField resignFirstResponder] ,它有一个关闭它的按钮。 (如 OK 或 Cancel) 这样您提供的键盘将被关闭。

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

【讨论】:

对不起,我不明白这一点。你能提供一小段代码吗? @Randomblue 在 ios 中,当您编写 [textfield resignFirstResponder] 时,它会从第一响应者中退出并隐藏键盘。所以在 alertdelegate 方法中你可以写 [textfield resignFirstResponder] 所以键盘会隐藏并且警报也会关闭..【参考方案4】:

我假设 UIAlertController 的跳下是在您按下键盘上的“返回”后它消失。如果是这样,我已经找到一种方法让警报和键盘从返回操作中顺利解除。

您需要在类文件中声明 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;


我已经对此进行了测试,应该可以完全按照您的要求工作。

谢谢, 吉姆

【讨论】:

谢谢你,@Jim Tierney。我用你的代码重新编辑了问题,结果显示在截图的后半部分。【参考方案5】:
   - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

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

【讨论】:

你提到的这个委托方法是针对 UIAlertview 的,UIAlertController 不使用它,因为它的解除将在 UIAlertController 使用的 UIAction 块中处理【参考方案6】:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

    

if (buttonIndex==1) 

        [[alertView textFieldAtIndex:0] resignFirstResponder];

         else 

            [[alertView textFieldAtIndex:0] resignFirstResponder];

        
    

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

【讨论】:

【参考方案7】:

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

- (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];

【讨论】:

【参考方案8】:

调动 UIAlertController 的 viewWillDisappear 方法,并在对应的文本字段上执行 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()
             

【讨论】:

以上是关于如何同时关闭 UIAlertController 和键盘?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SWIFT 中不执行任何操作就关闭 UIAlertController?

我们如何在没有用户输入的情况下创建和关闭 UIAlertController? (迅速)

在 Swift 中点击返回键时如何关闭 UIAlertController?

关闭 UIViewController 而不关闭其顶部的警报

如何在没有任何按钮的情况下以编程方式关闭 UIAlertController?

当 UIAlertController 在按钮按下时被关闭时收到通知