自定义 alert 的时候,没有作统一规划,都是实现一个 view,而后添加到 window 上。例如:git
UIView *alert = [[UIView alloc] initWithFrame:];
[window addSubView:alert];
复制代码
这样原本也没有什么问题,有一天需求来了要支持 Voice Over
,问题来了,直接盖上去的 view
不会自动聚焦,也就是手指左右滑动的时候,不能选中这个 view
。并且不能 alert
出来的时候,不能自动读出。github
而后想起之前 UIAlertView 显示的时候是有一个单独 window 的,因而也仿照 这样,本身建一个 window,来显示 alert,windows
self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.alertWindow.rootViewController = [[UIViewController alloc] init];
id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
// Applications that does not load with UIMainStoryboardFile might not have a window property:
if ([delegate respondsToSelector:@selector(window)]) {
// we inherit the main window's tintColor self.alertWindow.tintColor = delegate.window.tintColor; } self.alertWindow.hidden = YES; self.frame = self.alertWindow.bounds; // window level is above the top window (this makes the alert, if it's a sheet, show over the keyboard)
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
self.alertWindow.windowLevel = topWindow.windowLevel + 1;
[self.alertWindow makeKeyAndVisible];
[self.alertWindow addSubview:self];
[UIView animateWithDuration:0.25 animations:^{
self.alertWindow.hidden = NO;
} completion:nil];
复制代码
这样显示也正常,Voice Over
也能自动聚焦,可是 手指头不当心点到空白区域的时候,仍是会聚焦到下面的 view,不能只在 alert 上。 并且还有一个严重的问题 就是 自定义密码输入空间,键盘有时候不会自动弹起来,这个之前是没问题的,不知道跟这个会不会有关系。bash
仿照 UIAlertController 的方式,利用 presentViewController
来显示提示框,这个没有上面的问题,Voice over
也能自定聚焦,也不会点到下面的 view。效果还能够。ide
self.mShowInViewController.definesPresentationContext = YES;
self.mShowInViewController.providesPresentationContextTransitionStyle = YES;
if (!self.mShowViewController) {
UIViewController *vc = [[UIViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
backgroundView.backgroundColor = RGBA_COLOR_HEX(0x000000, 0.5);
vc.backgroundView = backgroundView;
if (self.alertType == CustomAlertTypeActionSheet) {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClickBackground)];
tap.delegate = self;
[self addGestureRecognizer:tap];
}
[vc.view addSubview:backgroundView];
vc.view.backgroundColor = [UIColor clearColor];
// vc.backgroundView.alpha = 0;
self.mShowViewController = vc;
}
}
if (!self.superview) {
[self.mShowViewController.view addSubview:self];
}
self.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
WEAKSELF
[self.mShowInViewController presentViewController:self.mShowViewController animated:NO completion:^{
[UIView animateWithDuration:0.25 animations:^{
weak_self.mShowViewController.view.alpha = 1;
} completion:^(BOOL finished) {
if (complete) {
complete(YES);
}
}];
}];
复制代码
使用 presentViewController
的时候,由哪一个ViewController
来 present 也是个问题,统一处理的话,用跟 UITabBarController
或者是 UINavigationController
都是不错的方案,例如:this
UIViewController * root = [UIApplication sharedApplication].delegate.window.rootViewController;
if ([root isKindOfClass:[UITabBarController class]]) {
UITabBarController *tab = (UITabBarController *)root;
if (tab.tabBar.hidden) {
//
UIViewController *selectedVC = tab.selectedViewController;
self.mShowInViewController = selectedVC;
} else {
self.mShowInViewController = root;
}
} else {
self.mShowInViewController = root;
}
复制代码
可是这里有问题,就是容易和其余的弹窗冲突,形成alert弹不出来,并且若是 alert 不释放的话,连弹屡次还容易 crashspa
Application tried to present modally an active controller
code
因此呢能够把 Window 和 present结合起来使用。事件
alertWindow 必定要在 alert 消失的时候给释放掉get
// method2: 问题是若是self 消失的时候不释放,那么 window 会一直存在接收事件,形成 rootWindow 没法接收事件
self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.alertWindow.rootViewController = [[UIViewController alloc] init];
id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
// Applications that does not load with UIMainStoryboardFile might not have a window property:
if ([delegate respondsToSelector:@selector(window)]) {
// we inherit the main window's tintColor self.alertWindow.tintColor = delegate.window.tintColor; } // window level is above the top window (this makes the alert, if it's a sheet, show over the keyboard)
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
self.alertWindow.windowLevel = topWindow.windowLevel + 1;
[self.alertWindow makeKeyAndVisible];
self.mShowInViewController = self.alertWindow.rootViewController;
复制代码
完整代码在这里