Show UIAlertController over keyboard

前端 未结 4 1186
不知归路
不知归路 2020-12-25 14:48

In iOS 8 and lower show a UIActionSheet when keyboard is presented will present the action sheet over the keyboard. With iOS 9 this is no longer the case.

相关标签:
4条回答
  • 2020-12-25 15:21

    Based on Leo Natan's answer, I've created a Swift extension for presenting an alert sheet over the keyboard.

    In my brief testing, the alertWindow is deallocated after the alert is dismissed, I believe because there's no strong reference to it outside of the alert. This means there's no need to hide or deallocate it in your UIAlertActions.

    extension UIAlertController {
    
        func presentOverKeyboard(animated: Bool, completion: (() -> Void)?) {
    
            let alertWindow = UIWindow(frame: UIScreen.mainScreen().bounds)
    
            // If you need a white/hidden/other status bar, use an appropriate VC.
            // You may not need a custom class, and you can just use UIViewController()
            alertWindow.rootViewController = whiteStatusBarVC()
    
            alertWindow.windowLevel = 10000001
            alertWindow.hidden = false
    
            // Set to a tint if you'd like
            alertWindow.tintColor = UIColor.greenColor()
    
            alertWindow.rootViewController?.presentViewController(self, animated: animated, completion: completion)
        }
    }
    
    private class whiteStatusBarVC: UIViewController {
        private override func preferredStatusBarStyle() -> UIStatusBarStyle {
            return .LightContent
        }
    }
    
    0 讨论(0)
  • 2020-12-25 15:24

    I have implemented exactly this in our app. The trick is to have the alert controller appear on a different window. This is how the UIActionSheet implementation does it, and works great on iOS 8, but on 9, Apple has moved the keyboard implementation to a window which has a very high window level (10000000). The fix is to give your alert window an even higher window level (as a custom double value, not using the provided constants).

    When using a custom window which will have transparency, make sure to read my answer here, regarding background color, to prevent window becoming black during rotation transitions.

    _alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    _alertWindow.rootViewController = [UIViewController new];
    _alertWindow.windowLevel = 10000001;
    _alertWindow.hidden = NO;
    _alertWindow.tintColor = [[UIWindow valueForKey:@"keyWindow"] tintColor];
    
    __weak __typeof(self) weakSelf = self;
    
    UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Test" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
    [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        weakSelf.alertWindow.hidden = YES;
        weakSelf.alertWindow = nil;
    }]];
    [alert addAction:[UIAlertAction actionWithTitle:@"Test" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        weakSelf.alertWindow.hidden = YES;
        weakSelf.alertWindow = nil;
    }]];
    
    [_alertWindow.rootViewController presentViewController:alert animated:YES completion:nil];
    

    0 讨论(0)
  • 2020-12-25 15:28

    The answer supplied by Leo is broken as of iOS 11, because Apple now prevents you from setting a windowLevel above 10000000. A fix is to implement a custom UIWindow and override the windowLevel receiver:

    @interface TopWindow : UIWindow @end
    
    @implementation TopWindow
    - (UIWindowLevel) windowLevel {
        return 20000000.000;
    }
    @end
    
    // usage:
    UIWindow* w = [[TopWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    w.rootViewController = [UIViewController new];
    w.hidden = NO;
    
    [w.rootViewController presentViewController:yourActionSheetController animated:YES completion:nil];
    

    This approach should be backwards compatible, but haven't tested all known versions. Happy hacking!

    0 讨论(0)
  • 2020-12-25 15:40

    use UIAlertController instead of UIActionSheet

    0 讨论(0)
提交回复
热议问题