Вдобавок ко всему: подпредставление UIWindow VS подпредставление UIViewController - PullRequest
27 голосов
/ 08 января 2012

Чтобы сделать UIView поверх всех представлений, например, поведение UIAlertView, лучший способ, который я вижу, - это поместить его в окно приложения, добавив представление к:

[[[UIApplication sharedApplication] delegate] window]

Тем не менее, недостатком, который я обнаружил, является то, что он не вращается автоматически.Для того, чтобы он работал по очереди, лучший способ сделать это - добавить представление в текущий AppDelegate window.navigationController / rootViewController, однако при этом он больше не будет находиться над всем.Скажем, когда отображается представление и появляется всплывающее окно modalViewController, модальное представление наверняка закроет представление.

Мой вопрос: возможно ли добавить подпредставление в самое верхнее окно и * 1011?* поддержка ориентации?Нужны ли в этом случае два набора файлов Nib?Как UIAlertView сочетает в себе магию и поддержку ориентации?Когда я смотрю в UIAlertView.h, я вижу, что на самом деле есть 2 UIWindows, один раз называется originalWindow, а другой - dimWindow.Есть ли место, где я могу найти исходный код для UIAlertView.m?

Ответы [ 3 ]

15 голосов
/ 13 февраля 2013

Лучшее решение, которое я нашел, - создать прозрачный вид контейнера, добавить этот контейнер в окно и поместить свое предупреждение внутри контейнера. Затем вы можете зарегистрироваться на UIApplicationWillChangeStatusBarOrientationNotification, чтобы получать события вращения и трансформировать контейнер; это позволяет вам независимо управлять кадром оповещения:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
     ...
     self.container = [[UIView alloc] initWithFrame:self.window.bounds];
     [self.container addSubview:self.alertView];
     [self.window addSubview:self.container];
     [[NSNotificationCenter defaultCenter] addObserver:self 
                                              selector:@selector(statusBarWillRotate:) 
                                                  name:UIApplicationWillChangeStatusBarOrientationNotification 
                                                object:nil];
     ...
}
...
- (void)statusBarWillRotate:(NSNotification *)theNotification
{
    CGFloat rotation = 0;
    switch ([notification[UIApplicationStatusBarOrientationUserInfoKey] intValue])
    {
        case UIInterfaceOrientationLandscapeLeft:
            rotation = -M_PI_2;
            break;
        case UIInterfaceOrientationLandscapeRight:
            rotation = M_PI_2;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            rotation = M_PI;
            break;
        case UIInterfaceOrientationPortrait: 
        default:
            rotation = 0;
            break;
    }
    CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(rotation);
    CGSize rotatedSize = CGRectApplyAffineTransform(self.window.bounds, rotationTransform).size;
    [UIView animationWithDuration:[UIApplication sharedApplication].statusBarOrientationAnimationDuration
                       animations:^{
         self.container.transform = rotationTransform;
         // Transform invalidates the frame, so use bounds/center
         self.container.bounds = CGRectMake(0, 0, rotatedSize.width, rotatedSize.height);
         self.container.center = CGPointMake(self.window.bounds.size.width / 2, self.window.bounds.size.height / 2);
     }];
}

Вы можете, если вы действительно хотите, создать совершенно новое окно со свойством windowLevel, установленным на UIWindowLevelAlert, которое будет гарантировать, что окно остается выше всех других представлений, включая клавиатуру, но управление окнами становится немного сложнее. сложно. Вышеуказанное решение должно быть достаточно для большинства нужд.

Проблема с простым добавлением вида контроллера представления в окно состоит в том, что не гарантируется получение всех сообщений поворота и view[Will|Did][Disa|A]ppear: сообщений, если только он не добавлен в контроллер вида иерархия через addChildViewController: на контроллере корневого представления.

4 голосов
/ 08 января 2012

Только первое подпредставление UIWindow получает информацию об изменениях ориентации.(

Ваш вопрос очень похож на этот:

Несколько представлений в UIWindow

Как видно из ответа, вы можетеЗарегистрируйтесь для получения уведомлений об изменениях ориентации и таким образом выполняйте ретрансляцию вашего «наверху» подпредставления.

2 голосов
/ 07 февраля 2013

Вот возможное решение, которое я объясняю в несколько шагов.

  1. Начнем с UIViewController унаследованного класса вместо UIView. Допустим, класс с именем TopViewController унаследован от UIViewController
  2. Поскольку вы не можете зарегистрировать ротацию устройства / интерфейса в унаследованном классе UIView, класс TopViewController, унаследованный от UIViewController, имеет методы, отвечающие на события просмотра поворота. События ротации теперь могут быть записаны.
  3. Наконец, вы можете поместить представление TopViewController поверх UIWindow, используя тот же метод, который вы упомянули в своем вопросе.

    [[[[UIApplication sharedApplication] delegate] window] addSubview:(TopViewController object).view];
    

Надеюсь, это поможет.

...