2012-01-08 3 views
27

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

[[[UIApplication sharedApplication] delegate] window] 

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

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

ответ

4

Сообщается только о первом подсмотре UIWindow об изменении ориентации. (< iOS8)

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

Multiple views in a UIWindow

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

+1

Как зарегистрировать представление устройства для получения события поворота? Это не View Controller, поэтому для него нет функций делегата. Нужно ли мне перехватывать UIDeviceOrientationDidChangeNotification для изменения соответствующей ориентации? –

2

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

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

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

Надеется, что это помогает.

+0

Свойство просмотра UIViewController также не будет вращаться. К сожалению. https://developer.apple.com/library/ios/qa/qa1688/_index.html – khunshan

15

Лучшее решение, которое я нашел, это создать прозрачный вид контейнера, добавить контейнер в окно и разместить предупреждение внутри контейнера. Затем вы можете зарегистрироваться для 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: на контроллере представления корня.

+0

У меня проблема с этим решением. Я не могу регистрировать штрихи в этом самом верхнем контейнере. Например, UIButtons не работает. – asendra

+0

@asendra Похоже, что ваше окно не является ключевым окном, но вы можете отправить свой вопрос более подробно. – Austin