it-swarm.com.ru

Получение ссылок на самый верхний вид/окно в приложении iOS

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

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

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

95
typeoneerror

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

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

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

36
Kris Markel

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

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

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

Все существующие ответы не попали в верхнюю часть окна. Но [[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];
    
45
an0

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

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

[[[[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. Если вы покажете лист действий непосредственно перед тем, как отобразить представление загрузки, 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
Miha Hribar

попробуй это

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

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

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