web-dev-qa-db-ja.com

iOSアプリケーションの一番上のビュー/ウィンドウへの参照を取得する

IOSアプリケーションで通知を表示するための再利用可能なフレームワークを作成しています。 UIAlertViewのように、アプリケーション内の他のすべての上に通知ビューを追加したいと思います。 NSNotificationイベントをリッスンし、それに応じてビューを追加するマネージャーを初期化するとき、アプリケーションの一番上のビューへの参照を取得する必要があります。これは私が今持っているものです:

_topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];

これはどのiOSアプリケーションでも機能しますか、それともトップビューを取得するより安全/より良い方法ですか?

97
typeoneerror

通常、これによりトップビューが表示されますが、ユーザーに表示される保証はありません。たとえば、画面外にあるか、アルファが0.0であるか、サイズが0x0である可能性があります。

また、keyWindowにはサブビューがないため、最初にテストする必要があります。これは珍しいことですが、不可能ではありません。

UIWindowはUIViewのサブクラスです。そのため、ユーザーに通知を表示したい場合は、addSubview:を使用してkeyWindowに直接追加すると、すぐに一番上のビューになります。これがあなたがやろうとしているものかどうかはわかりません。 (あなたの質問に基づいて、すでにこれを知っているようです。)

36
Kris Markel

他のすべての上にオーバーレイを表示したいときはいつでも、アプリケーションウィンドウの上に直接追加するだけです。

[[[UIApplication sharedApplication] keyWindow] addSubview:someView]
109
samvermette

問題には2つの部分があります。トップウィンドウ、トップウィンドウのトップビュー。

既存の回答はすべて、上部のウィンドウ部分を見逃していました。ただし、[[UIApplication sharedApplication] keyWindow]がトップウィンドウであるとは限りません。

  1. ウインドウ上部。同じwindowLevelを持つ2つのウィンドウがアプリに共存する可能性は非常に低いため、すべてのウィンドウをwindowLevelでソートし、一番上のウィンドウを取得できます。

    UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
        return win1.windowLevel - win2.windowLevel;
    }] lastObject];
    
  2. トップウィンドウのトップビュー。完了するだけです。質問ですでに指摘したように:

    UIView *topView = [[topWindow subviews] lastObject];
    
47
an0

実際、アプリケーションには複数のUIWindowが存在する可能性があります。たとえば、キーボードが画面上にある場合、[[UIApplication sharedApplication] windows]には少なくとも2つのウィンドウ(キーウィンドウとキーボードウィンドウ)が含まれます。

したがって、ビューを両方の上に表示する場合は、次のようなことをする必要があります。

[[[[UIApplication sharedApplication] windows] lastObject] addSubview:view];

(lastObjectには、最高のwindowLevel優先順位を持つウィンドウが含まれると仮定します)。

11
lorean

私はタイトルではなく議論ではなく、質問に固執しています。特定のポイントで上部に表示されるビューはどれですか?

@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で直接使用できます。

3
hfossli

アプリケーションが縦向きでのみ機能する場合、これで十分です。

[[[UIApplication sharedApplication] keyWindow] addSubview:yourView]

また、キーボードとステータスバーにはビューが表示されません。

キーボードまたはステータスバーの上に最上部のビューを取得する場合、または最上部のビューをデバイスで正しく回転できるようにする場合は、このフレームワークを試してください。

https://github.com/HarrisonXi/TopmostView

IOS7/8/9をサポートしています。

1
Harrison Xi

ロードビュー(たとえば、アクティビティインジケータービュー)を追加する場合は、UIWindowクラスのオブジェクトがあることを確認してください。ロードビューを表示する直前にアクションシートを表示すると、keyWindowUIActionSheetではなく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;
        }
    }
}
1
Miha Hribar

これを試して

UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];
0
Chandramani

画面内のすべての上にビューを追加する場合は、このコードを使用します。

[[UIApplication sharedApplication].keyWindow addSubView: yourView];
0
handiansom