在iOS 8.3及以上版本中,UIAlertView会导致keyboardWillShow和keyboardWillHide被调用两次。

3
在项目中,我遇到了这个问题。
其中一个控制器实现了keyboardWillShowkeyboardWillHide(来自苹果官方的标准代码管理键盘)。 在背景点击时,UIAlertView出现(基于某些验证),UIAlertView只有一个按钮,用于简单关闭UIAlertView
问题出在这里,在关闭UIAlertView时,keyboardWillShowkeyboardWillHide再次被调用。
以下是我遇到问题的代码。
#import "ViewController.h"

@interface ViewController () <UITextFieldDelegate>
{
   int timeCalledShow;
   int timeCalledHide;
}
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
- (IBAction)backgroundTapped:(id)sender;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardDidHideNotification
                                           object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {

    timeCalledShow+=1;
    NSLog(@"show Time Called %d", timeCalledShow);
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets;
    if (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])) {
        contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);
} else {
        contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.width), 0.0);
}
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}

- (void)keyboardWillHide:(NSNotification *)notification {
    timeCalledHide+=1;
    NSLog(@"Hide Time Called %d", timeCalledShow);
    self.scrollView.contentInset = UIEdgeInsetsZero;
    self.scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)backgroundTapped:(id)sender {
    [[[UIAlertView alloc] initWithTitle:@"Testing" message:@"Keyboard hide & show, due to alert view" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil] show];
    [self.view endEditing:YES];
}
@end

注意事项

  1. 我已经查看了keyboardWillShow called twice和类似的问题,但没有找到答案。
  2. 它在上运行良好。
  3. 这是测试代码的链接。

编辑 我已经知道了解决方法的代码。但真正的问题是,如何使UIAlertView触发keyboardWillShow通知。

编辑代码 我已经尝试过@Chonch建议的以下代码,但使用此代码后键盘永远不会关闭。也就是说,在关闭警报后键盘再次出现。

- (IBAction)backgroundTapped:(id)sender {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"testing" message:@"Keyboard" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                      handler:^(UIAlertAction * action) {}];

    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];
    [self.textField resignFirstResponder];
}

在苹果开发者论坛上发布的问题


UIAlertView在iOS8.0开始已经被弃用:https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIAlertView_Class/index.html - Rony Rozen
这可能会有所帮助 https://dev59.com/iIvda4cB1Zd3GeqPUQw6 - Abd Al-rhman Taher Badary
1
@pawan,它提供了一个解决方案,即在呈现警报视图之前取消订阅键盘通知,在您关闭警报视图后重新订阅通知。无论如何,这里有另一个解决方案:https://dev59.com/vYvda4cB1Zd3GeqPYFiR - Abd Al-rhman Taher Badary
@AbdAl-rhmanTaherBadary 我已经知道解决方法了,但我需要知道如何让警告视图触发键盘将显示的通知。 - Pawan Rai
1
由于它已被弃用,任何事情都可能发生,但肯定是一个错误,不过这里有一个很好的观察结果:https://dev59.com/vYvda4cB1Zd3GeqPYFiR#30500204 - Abd Al-rhman Taher Badary
显示剩余5条评论
3个回答

1
我刚刚解决了一个类似的问题。在警告框消失后,键盘仍然会弹出,这似乎是苹果的一个 bug。
有一个简单的解决方案: 如果你正在使用 AlertController,你可以将 animated 设置为 NO。
[self presentViewController:alert animated:NO completion:nil];

请告诉我它是否已经解决了您的问题。

1

UIAlertView存在漏洞,而且自从它被弃用以来可能一直存在问题。
请将其替换为UIAlertController,您的问题应该就会消失。


我认为您没有看到“编辑代码”部分,请在发布任何答案之前先进行检查。 - Pawan Rai
你能更具体一些吗? - Yariv Nissim

1
我不确定为什么会发生这种情况。可能与UIAlertView试图将键盘状态恢复到之前的状态有关。但请注意,额外的show/hide调用并没有造成任何伤害。而且通常情况下,您需要准备处理多个show调用,因为它们也会在键盘样式更改时出现。
如果您想摆脱它们,那么像Chonch建议的那样使用UIAlertController,并确保在警告框弹出之前解除键盘,那么它就可以正常工作了:
- (IBAction)backgroundTapped:(id)sender {
    [self.textField resignFirstResponder];

    alert = [UIAlertController alertControllerWithTitle:@"testing" message:@"Keyboard" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {}];

    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];
}

请注意,使用UIAlertController时,您还需要在视图控制器中保留对警报的引用,否则它将过早释放。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接