Отримання посилань на самий перегляд / вікно в додатку 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.