自前でViewControllerをモーダル表示させたい
iOSでモーダルでViewControllerを表示したい場合、
- (void)presentViewController:animated:completion:
を使うと思うのですが、時に、これを使わずにモーダル表示をさせたい場面があり、その対策の一つとして、専用のUIWindowクラスを作る手があります。
上記のメソッドに似た形で試しに作ってみたのがこちら。
任意のViewControllerを渡すと、それをモーダルっぽく表示してくれます。
ちなみにanimated=YESだと、ふわっとした感じで出てきます。
/**
@brief 与えられたViewControllerをアラートとして表示する
*/
- (void)presentAlertController:(UIViewController *)viewControllerToPresent
animated:(BOOL)animated
completion:(void (^)(void))completion {
dispatch_async(dispatch_get_main_queue(), ^{
UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.windowLevel = UIWindowLevelAlert;
window.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
window.rootViewController = viewControllerToPresent;
[window makeKeyAndVisible];
self.indicatorWindow = window;
if (animated) {
window.alpha = 0.1;
[UIView transitionWithView:window duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveEaseInOut
animations:^{
window.alpha = 1;
} completion:^(BOOL finished) {
if (completion) {
completion();
}
}];
}
});
}
UIWindowLevel?
さて、これだけであれば平和に解決なのですが、UIWindowにはwindowLevelというプロパティがあります。
これ、要するに「そのWindowがどれぐらい手前に出てくるか」というレベルです。
ちなみにリファレンスを見ると、こうなっておる。
const UIWindowLevel UIWindowLevelNormal;
const UIWindowLevel UIWindowLevelAlert;
const UIWindowLevel UIWindowLevelStatusBar;
typedef CGFloat UIWindowLevel;
簡単に言えば、
「通常のwindowよりも、アラートの方が常に手前に出る」
そして更に
「アラートよりも、ステータスバーの方が常に手前に出る」
ということです。それを決定しているのがこのUIWindowLevelなわけです。
通常Windowとアラートの間のレベルが欲しい!!
そうなんです。
実は、そもそも私が自前でモーダル表示のカテゴリメソッドを生やしたのは、
「通常のWindowよりは手前だけど、アラートよりは奥に出るWindowが欲しい」
という要望からでした。
しかし、windowLevelプロパティに設定できるのは上記の3種類だけ・・・?
いやいや、よ〜く見ると
typedef CGFloat UIWindowLevel;
と書いてあるじゃないですか。はい。こいつ、単なるCGFloatなんです。
というわけで、そしたら、
window.windowLevel = UIWindowLevelAlert;
の部分を、
window.windowLevel = UIWindowLevelAlert - 1;
に書き換えれば、アラートより奥にwindowが表示されるのでは??
あかんやん
しかし、それではうまくいきませんでした。
もう少し正確に言うと、このUIViewController上から更に普通のUIAlertViewを表示させようとしても、
全く何も起きなくなってしまいました。
なんであかんのかぜんぜんわからへん
ということで、色々とデバッグしてみたところ、実は
window.windowLevel = UIWindowLevelAlert - 4;
だとちゃんと動いたのです!!
-1と-4。
どういうことなのか。
ともかく、
iOSが「WindowLevelに差がある」と判断するには、最低でもWindowLevelの差が4以上は必要
という結論に現在至っております。
しかし理由は全くわかりません。
誰かご存知の方、ご教授いただければと思います。