beatrob
beatrob

Reputation: 93

iOS - UIAlertController hidden under keyboard

I have an UIAlertController presented from a UIViewController which is pushed in the UINavigationController as the last UIViewController. This UIAlertViewController has a UITextField in it.

My problem is that when I select the UITextField the keyboard shows up, but the UIAlertViewController stays centered, and partly hidden under the keyboard.

My code looks like this:

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

ScrenshotHidden UIAllertController

Upvotes: 9

Views: 2377

Answers (6)

Yuichi Kato
Yuichi Kato

Reputation: 891

I concluded that this should a bug of iOS, so I decided to handle it by creating a normal UIView. Here is a .xib file that I created for mocking UIAlertcontoller with UITextField in it. Hope your time will be saved some at least.

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

Upvotes: 0

Alexandr Kolesnik
Alexandr Kolesnik

Reputation: 2204

If I understood you, the problem is that alert is shown under keyboard. I think the problem is that the UIAlertController is shown on your viewController? but the keyboard is shown from rootViewController. Try this code to manage the problem

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)

I wrote extension, because in some cases the code above could not work

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
}

}

usage

    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)

Upvotes: 1

Dam
Dam

Reputation: 577

You can add [self.view endEditing:YES]; to be sure the keyboard won't be show.

Upvotes: -1

Kasper Munck
Kasper Munck

Reputation: 4191

The keyboard is presented in a dedicated window. So is an alert, your viewcontrollers (see you application delegate's window property) etc. It is the windowLevel of UIWindow instances that determine the z-order of the windows (i.e. how windows are presented above/below each other).

We have seen the same behaviour in our app where we use a custom window for custom alerts, which is always shown below the keyboard's window. It seems like window level behaviour has changed at some point during iOS 9/10 releases, so that the keyboard's window is always at the top of the window stack.

Since UIAlertController's window is managed by the system, there is likely no way for 3rd party developers to modify this behaviour.

To inspect the window level of the alert's window, however, you can reference its view's window's windowLevel property after you have presented it (eg in the presentation function's completion block). Perhaps even change it to a very large value in an attempt to force the alert's window level.

To track this issue you could duplicate this radar.

Upvotes: 0

Sommm
Sommm

Reputation: 531

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;
    }

You can also check these concept in apple documents. https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html

Upvotes: -3

Cjay
Cjay

Reputation: 1093

It should be automatically be adjusted. Check you view hierarchy

Upvotes: 5

Related Questions