15

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

当表单出现时,键盘和模式会以流畅的动画出现。关闭窗体时,modal消失,然后键盘消失。这使得键盘突然向下坠落。

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

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
}

提出和解雇

4

8 回答 8

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

结果:

在此处输入图像描述

PS:我使用旧警报的过渡代表进行演示,因为我无法重现原始动画。所以animatePresentation:从不使用方法。

于 2015-04-12T13:48:02.590 回答
9

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

迅速:

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

目标-C:

- (BOOL)canBecomeFirstResponder {
    return true;
}

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

于 2016-04-01T21:00:43.247 回答
2

它很简单。

如果您的UIAlertController委托存在于自身视图控制器中。然后你可以在 Dismiss AlertController 的委托方法中执行此操作。你可以[youtTextField resignFirstResponder]在你的 UIAlertController 对象中有一个关闭它的按钮。(如确定或取消),因此您提供的键盘将被取消。

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

于 2015-04-10T05:53:20.117 回答
1

我假设 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;

}

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

谢谢,吉姆

于 2015-04-12T08:36:20.043 回答
0
   - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

   { 
       [self.view endEditing:YES];
      // or you can write [yourtextfield refignFirstResponder]
       [alertView dismissWithClickedButtonIndex:buttonIndex animated:TRUE];
   }
于 2015-04-10T06:10:32.407 回答
0

Swizzle 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()
             }
于 2016-04-20T08:56:01.550 回答
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];

}

于 2016-04-07T12:35:37.913 回答
0
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

   { 

if (buttonIndex==1) {

        [[alertView textFieldAtIndex:0] resignFirstResponder];

        } else {

            [[alertView textFieldAtIndex:0] resignFirstResponder];

        }
    }

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

于 2015-08-12T07:45:51.083 回答