アラートっぽいのを表示するライブラリを作りたくなって,UIWindow
を使ってみた.
なんでwindowを使ったかというと,普通にviewにaddSubview:
するのだと常に前面に表示されている保証が無いし,ライブラリのくせに自分の管理してないviewの階層をいじくるのはちょっとアレかなあと思ったから.
UIWindow
とは
昨今のモダンな環境でiOSアプリを作ってるとUIWindow
を自分で作ることはまずないので気にしたこと無いかもしれないけど,UIWindow
は特別なUIView
でview階層のルートとなるviewのこと.
iOSアプリは例外なく全てのアプリが少なくともひとつのUIWindow
を持っている.
Xcode 3くらいまではテンプレートでwindowとってきてmakeKeyAndVisible
していたのでなんとなく覚えている人もいるかと思う.
Macと違ってiOSではひとつのアプリしかアクティブにならないから,基本的にwindowを増やしたいこととかほとんどないけど,オリジナルのアラートとかをスクリーン全体に重ねて表示したいってときとかに使える.
ちょうど,UIWindow
にはwindowLevel
ってプロパティがあって,オレオレアラートならUIWindowLevelAlert
を設定しておくといい具合になる.
基本的にaddSubview:
するのと同じ感覚で使えるし,windowを新しく作って表示するとアプリの状態をあまり意識せずにオーバーレイ表示ができて便利.
UIWindow
を表示する
UIWindow
を表示するときには,通常のviewと違ってmakeKeyAndVisible
を使う.
windowにはrootViewController
プロパティもあるけど,単純なアラート程度ならwindowに直接addSubview:
すればいいと思う.
UIWindow
はUIView
のサブクラスなのでだいたいいつもと同じ感覚で使える.
表示はこんな感じ.
- (void)showWindow { UIWindow *w = [UIWindow new]; w.frame = UIScreen.mainScreen.bounds; w.backgroundColor = [UIColor.blackColor colorWithAlphaComponent:0.2]; MyAlertView *alert = ... [w addSubview:alert]; [w makeKeyAndVisible]; self.window = w; }
windowに対してmakeKeyAndVisible
を呼ぶとそのwindowは key window になる.
key windowってはこれまたあ特別なwindowで,現在最前面に表示されているwindowだと解釈すればいい.
カレントのkey windowはUIApplication
のkeyWindow
プロパティで取得できるし,windowの階層はwindows
プロパティで取得できる.
UIWindow
を隠す
Macと同じ感覚だとresignKeyWindow
を呼ぶけど,iOSでは直接呼んではいけない.
resignKeyWindow
はkey windowじゃなくなったときの処理をするメソッド(dealloc
やdrawRect:
と同じような感じ).
resignKeyWindow Invoked automatically when the window resigns key window status; never invoke this method directly.
- (void)resignKeyWindow Discussion This method sends resignKeyWindow to the receiver’s first responder and posts UIWindowDidResignKeyNotification to the default notification center.
(UIWindow Class Referenceより抜粋)
じゃあどないして隠すかというと,こんな感じで隠したいwindowを破棄すると隠れる. ついでに古いやつをkey windowにしておこう.
- (void)removeWindow { UIApplication *app = UIApplication.sharedApplication; NSRange range = NSMakeRange(0, [app.windows indexOfObject:self.window] - 1); UIWindow *nextKeyWindow = [[app.windows subarrayWithRange:range] lastObject]; [nextkeywindow makeKeyAndVisible]; self.window = nil; // 保持していたやつを破棄 }
なんか釈然としないけどこれで隠れる.
この例ではwindows
から次のkey windowを探してきたけど,出すときに覚えておいてもいいと思う.
まとめ
- なんかオーバーレイで表示したいときは
UIWindow
を使うと便利 - 消すときは自分で
resignKeyWindow
を呼んではいけない