Получение ссылки на самый верхний вид / окно в приложении iOS - PullRequest
97 голосов
/ 02 октября 2010

Я создаю многоразовую платформу для отображения уведомлений в приложении iOS. Я бы хотел, чтобы представления уведомлений добавлялись поверх всего остального в приложении, что-то вроде UIAlertView. Когда я запускаю менеджер, который прослушивает события NSNotification и добавляет представления в ответ, мне нужно получить ссылку на самый верхний вид в приложении. Вот что у меня на данный момент:

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

Будет ли это работать для любого приложения iOS или это более безопасный / лучший способ получить вид сверху?

Ответы [ 9 ]

109 голосов
/ 02 октября 2010

Всякий раз, когда я хочу отобразить какое-либо наложение поверх всего остального, я просто добавляю его поверх окна приложения:

[[[UIApplication sharedApplication] keyWindow] addSubview:someView]
47 голосов
/ 08 ноября 2011

Есть две части проблемы: верхнее окно, вид сверху на верхнее окно.

Все существующие ответы пропущены в верхней части окна. Но [[UIApplication sharedApplication] keyWindow] не обязательно будет верхним окном.

  1. Верхнее окно. Маловероятно, что для приложения будут сосуществовать два окна с одинаковым windowLevel, поэтому мы можем отсортировать все окна по windowLevel и получить самое верхнее.

    UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
        return win1.windowLevel - win2.windowLevel;
    }] lastObject];
    
  2. Вид сверху в верхнем окне. Просто чтобы быть полным. Как уже указывалось в вопросе:

    UIView *topView = [[topWindow subviews] lastObject];
    
36 голосов
/ 02 октября 2010

Обычно это дает вам вид сверху, но нет никакой гарантии, что он виден пользователю. Он может быть вне экрана, иметь альфа 0,0 или иметь размер 0x0, например.

Может также случиться, что у keyWindow нет подпредставлений, поэтому вам, вероятно, следует сначала проверить это. Это было бы необычно, но это не невозможно.

UIWindow является подклассом UIView, поэтому, если вы хотите убедиться, что ваше уведомление является видимым для пользователя, вы можете добавить его непосредственно в keyWindow, используя addSubview:, и оно сразу будет самым верхним видом. Я не уверен, что это то, что вы хотите сделать, хотя. (Судя по вашему вопросу, похоже, вы это уже знаете.)

11 голосов
/ 29 февраля 2012

На самом деле в вашем приложении может быть несколько окон UIWindow.Например, если на экране есть клавиатура, то [[UIApplication sharedApplication] windows] будет содержать как минимум два окна (ваше окно клавиш и окно клавиатуры).

Так что, если вы хотите, чтобы ваше представление отображалось поверх обоих,вы должны сделать что-то вроде:

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

(при условии, что lastObject содержит окно с самым высоким приоритетом windowLevel).

3 голосов
/ 06 февраля 2013

Я придерживаюсь вопроса, как говорится в заголовке, а не в обсуждении.Какой вид виден сверху в любой заданной точке?

@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 в качестве получателя.

1 голос
/ 25 февраля 2016

Если ваше приложение работает только в портретной ориентации, этого достаточно:

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

И ваше представление не будет отображаться через клавиатуру и строку состояния.

Если вы хотите получитьсамый верхний вид, который через клавиатуру или строку состояния, или вы хотите, чтобы самый верхний вид мог правильно вращаться вместе с устройствами, попробуйте следующую структуру:

https://github.com/HarrisonXi/TopmostView

Он поддерживает iOS7 / 8 / 9.

1 голос
/ 03 ноября 2015

Если вы добавляете представление загрузки (например, представление индикатора активности), убедитесь, что у вас есть объект класса 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;
        }
    }
}
0 голосов
/ 20 марта 2017

Просто используйте этот код, если вы хотите добавить вид выше всего на экране.

[[UIApplication sharedApplication].keyWindow addSubView: yourView];
0 голосов
/ 18 августа 2016

попробуйте

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