在键盘上显示 UIAlertController
Show UIAlertController over keyboard
在 iOS 8 及更低版本中显示 UIActionSheet
当键盘出现时将在键盘上显示动作 sheet。 iOS 9 不再是这种情况。
在我的应用程序中,我们有一个聊天功能,并希望通过键盘显示一个动作。我们曾经使用 UIActionSheet
,在 iOS 8 之前工作正常。在 iOS 9 中,操作 sheet 出现在键盘后面。 UIActionSheet
和 UIAlertController
.
我都试过了
我们想要的是像 messages.app 中那样的操作 sheet
我已经尝试将操作 sheet 放在它自己的 window 中并覆盖 canBecomeFirstResponder
这只会让键盘消失。
我已经在我们的应用程序中实现了这一点。诀窍是让警报控制器出现在不同的 window 上。这就是 UIActionSheet
实现的方式,并且在 iOS 8 上运行良好,但在 9 上,Apple 已将键盘实现移至具有非常高 window 的 window ] 水平(10000000)。解决方法是为您的警报 window 提供更高的 window 级别(作为自定义双精度值,不使用提供的常量)。
当使用具有透明度的自定义 window 时,请务必阅读 my answer here 关于背景颜色的内容,以防止 window 在旋转过渡期间变黑。
_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];
使用 UIAlertController 而不是 UIActionSheet
根据 Leo Natan 的回答,我创建了一个 Swift 扩展,用于通过键盘显示警报 sheet。
在我的简短测试中,alertWindow 在解除警报后被释放,我相信是因为在警报之外没有对它的强引用。这意味着无需在您的 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
}
}
从 iOS 11 起,Leo 提供的答案已失效,因为 Apple 现在阻止您将 windowLevel 设置为高于 10000000
。解决方法是实现自定义 UIWindow 并覆盖 windowLevel
接收器:
@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];
此方法应该是向后兼容的,但尚未测试所有已知版本。快乐黑客!
在 iOS 8 及更低版本中显示 UIActionSheet
当键盘出现时将在键盘上显示动作 sheet。 iOS 9 不再是这种情况。
在我的应用程序中,我们有一个聊天功能,并希望通过键盘显示一个动作。我们曾经使用 UIActionSheet
,在 iOS 8 之前工作正常。在 iOS 9 中,操作 sheet 出现在键盘后面。 UIActionSheet
和 UIAlertController
.
我们想要的是像 messages.app 中那样的操作 sheet
我已经尝试将操作 sheet 放在它自己的 window 中并覆盖 canBecomeFirstResponder
这只会让键盘消失。
我已经在我们的应用程序中实现了这一点。诀窍是让警报控制器出现在不同的 window 上。这就是 UIActionSheet
实现的方式,并且在 iOS 8 上运行良好,但在 9 上,Apple 已将键盘实现移至具有非常高 window 的 window ] 水平(10000000)。解决方法是为您的警报 window 提供更高的 window 级别(作为自定义双精度值,不使用提供的常量)。
当使用具有透明度的自定义 window 时,请务必阅读 my answer here 关于背景颜色的内容,以防止 window 在旋转过渡期间变黑。
_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];
使用 UIAlertController 而不是 UIActionSheet
根据 Leo Natan 的回答,我创建了一个 Swift 扩展,用于通过键盘显示警报 sheet。
在我的简短测试中,alertWindow 在解除警报后被释放,我相信是因为在警报之外没有对它的强引用。这意味着无需在您的 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
}
}
从 iOS 11 起,Leo 提供的答案已失效,因为 Apple 现在阻止您将 windowLevel 设置为高于 10000000
。解决方法是实现自定义 UIWindow 并覆盖 windowLevel
接收器:
@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];
此方法应该是向后兼容的,但尚未测试所有已知版本。快乐黑客!