Отримання посилань на самий перегляд / вікно в додатку 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)повернувся і в час, viewDidLoadі в viewWillAppear:часи. viewDidAppear:
— Запізно

це працює, коли ми представляємо контролер перегляду ?. Чи буде доданий підперегляд показаний над представленим контролером перегляду?
— Пратюша Терлі

Це не піде над клавіатурою, хоч lastObject робить.
— Ser Pounce

Цей фреймворк може працювати в усіх напрямках. І піде вище клавіатури. github.com/HarrisonXi/TopmostView
— Harrison Xi

47

Є дві частини проблеми: верхнє вікно, вид зверху на верхнє вікно.

Усі наявні відповіді пропустили верхню частину вікна. Але [[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];

5
Це рішення перестало працювати для мене, коли UIAlertViews почала грати - вони, здається, залишають порожнє інтерфейс UIWindow, тому я повернувся назад доtopView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
— Gereon

4
Це не працює, якщо клавіатура ввімкнена. Оскільки це буде саме верхнє вікно
— ентропія

@Gereon, переконайтеся, що ви не маєте чіткої посилання на будь-який UIAlertView. Якщо це не слабка посилання, UIAlertOverlayWindow все ще буде перебувати в ієрархії і розпізнаватися як ключове вікно, але додані до нього підгляди не відображатимуться.
— бджола

Значення topWindow не є належним у випадку iOS 8
— Mehul Thakkar

11

Насправді у вашій програмі може бути більше одного вікна UIW. Наприклад, якщо клавіатура на екрані, то вона [[UIApplication sharedApplication] windows]буде містити щонайменше два вікна (ваше клавіатурне вікно та вікно клавіатури).

Тож якщо ви хочете, щоб ваш погляд з'явився на обох, тоді вам потрібно зробити щось на кшталт:

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

(Припустимо, що LastObject містить вікно з найвищим пріоритетом windowLevel).


[[[UIApplication sharedApplication] вікна] lastObject] значення не власне в разі ІС 8
— Mehul Thakkar

Я почав використовувати це, але, здається, іноді вікно клавіатури існує, але не відображається, і тоді мій погляд зовсім не відображається!
— Тераділ

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 як приймачем.


topWindow надає неправильне значення у випадку iOS 8. Чи можете ви, будь ласка, оновити свою відповідь для iOS 8
— Мехул Тхакар

1
Я не встигаю це дізнатися. Якщо ви можете, ви можете оновити цю публікацію.
— hfossli

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];

Про властивість Windows: "Цей ресурс містить масив об'єктів 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;
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.