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


97

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

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

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

回答:


36

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

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

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


111

他の上にオーバーレイを表示したい場合は、アプリケーションウィンドウの上に直接追加します。

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

9
:のみ縦向きに働く..あなたは、このような回転などを気にしなきゃstackoverflow.com/questions/2508630/...
hfossli

1
私は取得しています(null)私のiOS-8アプリ(絵コンテの問題?)任意のヒントに?ありがとう!(注:(null)の両方で返されるviewDidLoadviewWillAppear:、時間。 viewDidAppear:遅すぎる。
Olie

これは、ビューコントローラーを表示するときに機能しますか?追加されたサブビューは、表示されたビューコントローラーの上に表示されますか?
Pratyusha Terli 2015年

これはキーボードを超えることはありませんが、lastObjectはそうします。
Ser Pounce、2015年

このフレームワークは、あらゆる方向で機能します。そしてキーボードの上に行きます。github.com/HarrisonXi/TopmostView
Harrison Xi

47

問題の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];

5
UIAlertViewsが遊びに来たら、このソリューションは、私のために動作を停止-彼らは後ろemtpy UIWindowを残すように見える、私は戻って戻ってtopView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
ジェレオン

4
キーボードが上にある場合、これは機能しません。それが最上位のウィンドウになる
エントロピー

@ Gereon、UIAlertViewへの強い参照を保持していないことを確認してください。弱い参照でない場合、UIAlertOverlayWindowは階層内にあり、キーウィンドウとして認識されますが、それに追加されたサブビューは表示されません。
beebcon 14

iOS 8の場合、topWindow値は適切ではありません
Mehul Thakkar

11

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

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

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

(lastObjectにwindowLevel優先度が最も高いウィンドウが含まれていると想定)。


[[[UIApplication sharedApplication] windows] lastObject]値がiOS 8の場合に適切ではない
Mehul Thakkar

私はこれを使い始めましたが、キーボードウィンドウが存在しているのに表示されないことがあり、ビューがまったく表示されません。
teradyl 2016年

3

タイトルでは議論ではなく、質問に固執しています。任意の点でどのビューが上部に表示されますか?

@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をレシーバーとして直接使用できます。


iOS 8の場合、topWindowの値が正しくありません
。iOS8の

1
調べる時間がない。もしそうなら、あなたはこの投稿を自由に更新できます。
hfossli 2014

1

ロードビュー(アクティビティインジケータビューなど)を追加する場合は、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;
        }
    }
}

1

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

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

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

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

https://github.com/HarrisonXi/TopmostView

iOS7 / 8/9に対応しています。


0

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

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

0

これを試して

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

ウィンドウプロパティについて:「このプロパティには、アプリの既存のすべてのウィンドウに対応するNSWindowオブジェクトの配列が含まれています。この配列には、画面に表示されているかどうかに関係なく、画面上のウィンドウと画面外のウィンドウがすべて含まれています。順序の保証はありません。配列内のウィンドウの。」
スティーブンフィッシャー

0
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if (![NSStringFromClass([keyWindow class]) isEqualToString:@"UIWindow"]) {

    NSArray *windows = [UIApplication sharedApplication].windows;
    for (UIWindow *window in windows) {
        if ([NSStringFromClass([window class]) isEqualToString:@"UIWindow"]) {
            keyWindow = window;
            break;
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.