iOS - 隐藏在键盘下的 UIAlertController

iOS - UIAlertController hidden under keyboard

我有一个 UIAlertController 来自 UIViewController 的呈现,它作为最后一个 UIViewController 被推入 UINavigationController。这个UIAlertViewController里面有一个UITextField

我的问题是,当我 select 时,UITextField 键盘出现,但 UIAlertViewController 保持居中,部分隐藏在键盘下方。

我的代码如下所示:

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Enter Your PIN" message:@"Please enter your PIN!" preferredStyle:UIAlertControllerStyleAlert];

[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        [textField setSecureTextEntry:YES];
    }];

UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"Confirm"
                                                       style:UIAlertActionStyleDefault
                                                     handler:^(UIAlertAction * _Nonnull action) {  }];


UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
                                                           style:UIAlertActionStyleCancel
                                                         handler:^(UIAlertAction * _Nonnull action) {
                                                         }];
[alert addAction:okAction];
[alert addAction:cancelAction];
[self presentViewController:alert animated:YES completion:nil];

截图

应该是自动调整的。 检查您的视图层次结构

You can manage your keyboard based on textField location.


// Call this method somewhere in your view controller in **viewdidload** method

    - (void)registerForKeyboardNotifications
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                selector:@selector(keyboardWasShown:)
                name:UIKeyboardDidShowNotification object:nil];

       [[NSNotificationCenter defaultCenter] addObserver:self
                 selector:@selector(keyboardWillBeHidden:)
                 name:UIKeyboardWillHideNotification object:nil];

    }

//Add in your View Controller which Called when the UIKeyboardDidShowNotification is sent.

    - (void)keyboardWasShown:(NSNotification*)aNotification
    {
        NSDictionary* info = [aNotification userInfo];
        CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;

        // If active text field is hidden by keyboard, scroll it so it's visible
        // Your app might not need or want this behavior.
        CGRect aRect = self.view.frame;
        aRect.size.height -= kbSize.height;
        if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
            [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
        }
    }
// Add in your View Controller which Called when the UIKeyboardWillHideNotification is sent

    - (void)keyboardWillBeHidden:(NSNotification*)aNotification
    {
        UIEdgeInsets contentInsets = UIEdgeInsetsZero;
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

Initialize UITextField * activeField;

Additional methods for tracking the active text field.

    - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        activeField = textField;
    }

    - (void)textFieldDidEndEditing:(UITextField *)textField
    {
        activeField = nil;
    }

你也可以在苹果文档中查看这些概念。 https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html

如果我理解你的话,问题是键盘下方显示了警报。我认为问题在于 UIAlertController 显示在您的 viewController 上?但是键盘是从 rootViewController 显示的。试试这个代码来解决问题

let alert = UIAlertController(title: "Title", message: NSLocalizedString("Message", comment: ""), preferredStyle: .alert)
                let okAction = UIAlertAction(title: "OK", style: .default) { action in }
alert.addAction(okAction)
let rootViewController: UIViewController = UIApplication.shared.windows.last!.rootViewController!
rootViewController.present(alert, animated: true, completion: nil)

我写了扩展,因为在某些情况下上面的代码无法工作

extension UIApplication {

class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
    if let nav = base as? UINavigationController {
        return topViewController(base: nav.visibleViewController)
    }
    if let tab = base as? UITabBarController {
        let moreNavigationController = tab.moreNavigationController
        if let top = moreNavigationController.topViewController, top.view.window != nil {
            return topViewController(base: top)
        } else if let selected = tab.selectedViewController {
            return topViewController(base: selected)
        }
    }
    if let presented = base?.presentedViewController {
        return topViewController(base: presented)
    }
    return base
}

}

用法

    let alert = UIAlertController(title: NSLocalizedString(title, comment: ""), message: message, preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
    UIApplication.topViewController()?.present(alert, animated: true, completion: nil)

键盘显示在专用 window 中。警报、您的视图控制器(请参阅应用程序委托的 window 属性)等也是如此。UIWindow 实例中的 windowLevel 决定了 windows(即 windows 如何相互呈现 above/below)。

我们在我们的应用程序中看到了相同的行为,我们使用自定义 window 作为自定义警报,它始终显示在键盘 window 下方。 window 级别的行为似乎在 iOS 9/10 版本的某个时候发生了变化,因此键盘的 window 始终位于 window 堆栈的顶部。

由于 UIAlertController 的 window 由系统管理,因此第 3 方开发人员可能无法修改此行为。

要检查警报 window 的 window 级别,但是,您可以参考其 viewwindowwindowLevel 属性 在你呈现它之后(例如在呈现函数的完成块中)。甚至可能将其更改为一个非常大的值,以试图强制警报的 window 级别。

要跟踪此问题,您可以复制 this radar

您可以添加 [self.view endEditing:YES]; 以确保键盘不会显示。

我断定这应该是 iOS 的一个错误,所以我决定通过创建一个普通的 UIView 来处理它。这是我创建的一个 .xib 文件,用于模拟其中包含 UITextField 的 UIAlertcontoller。希望你的时间至少能节省一些。

https://www.dropbox.com/s/kg2nf9qcm4flhk0/AlertviewWithTextield.xib?dl=0