IOSアプリケーションで通知を表示するための再利用可能なフレームワークを作成しています。 UIAlertViewのように、アプリケーション内の他のすべての上に通知ビューを追加したいと思います。 NSNotificationイベントをリッスンし、それに応じてビューを追加するマネージャーを初期化するとき、アプリケーションの一番上のビューへの参照を取得する必要があります。これは私が今持っているものです:
_topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
これはどのiOSアプリケーションでも機能しますか、それともトップビューを取得するより安全/より良い方法ですか?
通常、これによりトップビューが表示されますが、ユーザーに表示される保証はありません。たとえば、画面外にあるか、アルファが0.0であるか、サイズが0x0である可能性があります。
また、keyWindowにはサブビューがないため、最初にテストする必要があります。これは珍しいことですが、不可能ではありません。
UIWindowはUIViewのサブクラスです。そのため、ユーザーに通知を表示したい場合は、addSubview:
を使用してkeyWindowに直接追加すると、すぐに一番上のビューになります。これがあなたがやろうとしているものかどうかはわかりません。 (あなたの質問に基づいて、すでにこれを知っているようです。)
他のすべての上にオーバーレイを表示したいときはいつでも、アプリケーションウィンドウの上に直接追加するだけです。
[[[UIApplication sharedApplication] keyWindow] addSubview:someView]
問題には2つの部分があります。トップウィンドウ、トップウィンドウのトップビュー。
既存の回答はすべて、上部のウィンドウ部分を見逃していました。ただし、[[UIApplication sharedApplication] keyWindow]
がトップウィンドウであるとは限りません。
ウインドウ上部。同じwindowLevel
を持つ2つのウィンドウがアプリに共存する可能性は非常に低いため、すべてのウィンドウをwindowLevel
でソートし、一番上のウィンドウを取得できます。
UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
return win1.windowLevel - win2.windowLevel;
}] lastObject];
トップウィンドウのトップビュー。完了するだけです。質問ですでに指摘したように:
UIView *topView = [[topWindow subviews] lastObject];
実際、アプリケーションには複数のUIWindowが存在する可能性があります。たとえば、キーボードが画面上にある場合、[[UIApplication sharedApplication] windows]
には少なくとも2つのウィンドウ(キーウィンドウとキーボードウィンドウ)が含まれます。
したがって、ビューを両方の上に表示する場合は、次のようなことをする必要があります。
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:view];
(lastObjectには、最高のwindowLevel優先順位を持つウィンドウが含まれると仮定します)。
私はタイトルではなく議論ではなく、質問に固執しています。特定のポイントで上部に表示されるビューはどれですか?
@implementation UIView (Extra)
- (UIView *)findTopMostViewForPoint:(CGPoint)point
{
for(int i = self.subviews.count - 1; i >= 0; i--)
{
UIView *subview = [self.subviews objectAtIndex:i];
if(!subview.hidden && CGRectContainsPoint(subview.frame, point))
{
CGPoint pointConverted = [self convertPoint:point toView:subview];
return [subview findTopMostViewForPoint:pointConverted];
}
}
return self;
}
- (UIWindow *)topmostWindow
{
UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
return win1.windowLevel - win2.windowLevel;
}] lastObject];
return topWindow;
}
@end
レシーバーとしてのUIWindowまたはレシーバーとしてのUIViewで直接使用できます。
アプリケーションが縦向きでのみ機能する場合、これで十分です。
[[[UIApplication sharedApplication] keyWindow] addSubview:yourView]
また、キーボードとステータスバーにはビューが表示されません。
キーボードまたはステータスバーの上に最上部のビューを取得する場合、または最上部のビューをデバイスで正しく回転できるようにする場合は、このフレームワークを試してください。
https://github.com/HarrisonXi/TopmostView
IOS7/8/9をサポートしています。
ロードビュー(たとえば、アクティビティインジケータービュー)を追加する場合は、UIWindowクラスのオブジェクトがあることを確認してください。ロードビューを表示する直前にアクションシートを表示すると、keyWindow
はUIActionSheet
ではなくUIWindow
になります。また、アクションシートがなくなるので、読み込みビューも一緒になくなります。または、それが私に問題を引き起こしていました。
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if (![NSStringFromClass([keyWindow class]) isEqualToString:@"UIWindow"]) {
// find uiwindow in windows
NSArray *windows = [UIApplication sharedApplication].windows;
for (UIWindow *window in windows) {
if ([NSStringFromClass([window class]) isEqualToString:@"UIWindow"]) {
keyWindow = window;
break;
}
}
}
これを試して
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
画面内のすべての上にビューを追加する場合は、このコードを使用します。
[[UIApplication sharedApplication].keyWindow addSubView: yourView];