3

Я написал простой контроллер просмотра, который показывает модальное всплывающее диалоговое окно. Поскольку он создает новое окно, чтобы проложить весь экран, я добавил наблюдателя UIDeviceOrientationDidChangeNotification, который вычисляет, как поворачивать вид, используя CGAffineTransformMakeRotation(). И это работает.Почему не всегда регистрируется UIDeviceOrientationDidChangeNotification?

В основном. Недостатком является то, что я могу поиграть с ориентацией и заставить его встать боком или перевернуться. Просмотрите номер this 18s video, демонстрирующий проблему. При отладке кажется, что иногда уведомление не срабатывает или, по крайней мере, не вызывает метод обратного вызова, который его прослушивает.

Должно быть, мне что-то не хватает, потому что если вы снова посмотрите на видео, вы заметите, что вид сзади делает правильно вращается. Этот управляется -willAnimateRotationToInterfaceOrientation:duration:. Как правило, метод контроллера iOS всегда называется правильно (предположительно управляемый наблюдателем UIDeviceOrientationDidChangeNotification в UIViewController), но мой собственный код не является?

ответ

0

Я исправил эту проблему, исключив использование UIDeviceOrientationDidChangeNotification. Вместо этого я создаю подкласс UIViewController и сделаю настраиваемое представление его представлению. Затем он просто выполняет -willAnimateRotationToInterfaceOrientation:duration: для вращения. Это на самом деле менее сложный код для меня. Тем не менее, для создания произвольного UIViewController это просто попытка использовать авторотацию в том, что по существу является клоном presentModalViewController. Кажется, UIDeviceOrientationDidChangeNotification должен работать правильно. Я ожидаю, что есть способ заставить его вести себя, но я еще не нашел его. :-(

+0

Обратите внимание, что '-presentModalViewController' принимает * контроллер *. События отправляются контроллерам в главном окне. UIWindow содержит массив корневых контроллеров, но по какой-то причине только пересылает эти события в первый элемент в этом списке ...: o ( –

+0

UIDeviceOrientationDidChangeNotification называется слишком много времени. Решение Джима намного лучше. – Vinzius

+0

@ Vinzius-I пытался адаптировать мой класс для использования решения Jim, но не смог заставить его работать. Он по-прежнему будет вращаться соответствующим образом, как вы можете видеть на [видео] (http://www.youtube.com/watch?v=m_IvFAkdfuA) Я отправил его с помощью своего решения. Поверьте мне, я предпочел бы использовать этот подход, чем это обходное решение. – theory

0

UIDeviceOrientation имеет несколько значений, которые не отображаются на UIInterfaceOrientation:

UIDeviceOrientationUnknown, 
UIDeviceOrientationFaceUp,    // Device oriented flat, face up 
UIDeviceOrientationFaceDown    // Device oriented flat, face down 

Возможно ли, что уведомление обратного вызова стрельбы, но эти случаи не обрабатываются?

Если контроллер вида имеет доступ к окну - он может перенаправить обратный вызов didRotate в окно вручную.

+0

Увы, нет.Я использую 'self.interfaceOrientation', а не UIDeviceOrientation, потому что, когда я проверяю последний, это * путь * чувствителен. Он меняет ориентацию при малейшем движении устройства. То есть проблема * намного хуже, когда я использую UIDeviceOrientation. – theory

+0

Предполагаете ли вы, что я вместо этого называю '-willAnimateRotationToInterfaceOrientation: duration:' методом обратного вызова 'UIDeviceOrientationDidChangeNotification'? Это может быть хорошо, но, увы, похоже, что мой метод уведомления либо не вызывается системой, либо 'self.interfaceOrientation' является неправильным значением, и это то, что заставляет его выбраться из-под удара. – theory

+0

Я вижу - не знаю, почему уведомления не будут получены. В любом случае методы willRotate/didRotate автовращающегося UIViewController должны быть надежным временем для ручного поворота модального диалога. – dstnbrkr

12

Я использовал UIApplicationWillChangeStatusBarOrientationNotification в Kobo, что похоже на трюк. Это намного надежнее, потому что вы хотите соответствовать выбранной ориентации пользовательского интерфейса, не обязательно там, где это устройство. Другими словами, вы может позволить Apple решить, когда вы должны переориентировать свое окно.

Вот несколько фрагментов кода кода всплывающего окна приложения Kobo на iPad (UIAlertView выглядит красиво на iPad, поэтому Richard Penner написал лучший вариант). несколько сбоев с более поздними версиями iOS и необходимость отображения этих диалогов в разных ситуациях (все вокруг ориентации IIRC), мне пришлось настроить его, чтобы сидеть прямо внутри UIWindow, что означало дублирование всей логики преобразования ориентации.

Этот код исходит от UIViewController, чей вид попадает прямо в текущее окно.

- (void) presentDialogWindow 
{ 
    // register for orientation change notification 
    [[NSNotificationCenter defaultCenter] addObserver: self 
              selector: @selector(orientationWillChange:) 
               name: UIApplicationWillChangeStatusBarOrientationNotification 
               object: nil]; 
    [[NSNotificationCenter defaultCenter] addObserver: self 
              selector: @selector(orientationDidChange:) 
               name: UIApplicationDidChangeStatusBarOrientationNotification 
               object: nil]; 
} 

- (void) orientationWillChange: (NSNotification *) note 
{ 
    UIInterfaceOrientation current = [[UIApplication sharedApplication] statusBarOrientation]; 
    UIInterfaceOrientation orientation = [[[note userInfo] objectForKey: UIApplicationStatusBarOrientationUserInfoKey] integerValue]; 
    if ([self shouldAutorotateToInterfaceOrientation: orientation] == NO) 
     return; 

    if (current == orientation) 
     return; 

    // direction and angle 
    CGFloat angle = 0.0; 
    switch (current) 
    { 
     case UIInterfaceOrientationPortrait: 
     { 
      switch (orientation) 
      { 
       case UIInterfaceOrientationPortraitUpsideDown: 
        angle = (CGFloat)M_PI; // 180.0*M_PI/180.0 == M_PI 
        break; 
       case UIInterfaceOrientationLandscapeLeft: 
        angle = (CGFloat)(M_PI*-90.0)/180.0; 
        break; 
       case UIInterfaceOrientationLandscapeRight: 
        angle = (CGFloat)(M_PI*90.0)/180.0; 
        break; 
       default: 
        return; 
      } 
      break; 
     } 
     case UIInterfaceOrientationPortraitUpsideDown: 
     { 
      switch (orientation) 
      { 
       case UIInterfaceOrientationPortrait: 
        angle = (CGFloat)M_PI; // 180.0*M_PI/180.0 == M_PI 
        break; 
       case UIInterfaceOrientationLandscapeLeft: 
        angle = (CGFloat)(M_PI*90.0)/180.0; 
        break; 
       case UIInterfaceOrientationLandscapeRight: 
        angle = (CGFloat)(M_PI*-90.0)/180.0; 
        break; 
       default: 
        return; 
      } 
      break; 
     } 
     case UIInterfaceOrientationLandscapeLeft: 
     { 
      switch (orientation) 
      { 
       case UIInterfaceOrientationLandscapeRight: 
        angle = (CGFloat)M_PI; // 180.0*M_PI/180.0 == M_PI 
        break; 
       case UIInterfaceOrientationPortraitUpsideDown: 
        angle = (CGFloat)(M_PI*-90.0)/180.0; 
        break; 
       case UIInterfaceOrientationPortrait: 
        angle = (CGFloat)(M_PI*90.0)/180.0; 
        break; 
       default: 
        return; 
      } 
      break; 
     } 
     case UIInterfaceOrientationLandscapeRight: 
     { 
      switch (orientation) 
      { 
       case UIInterfaceOrientationLandscapeLeft: 
        angle = (CGFloat)M_PI; // 180.0*M_PI/180.0 == M_PI 
        break; 
       case UIInterfaceOrientationPortrait: 
        angle = (CGFloat)(M_PI*-90.0)/180.0; 
        break; 
       case UIInterfaceOrientationPortraitUpsideDown: 
        angle = (CGFloat)(M_PI*90.0)/180.0; 
        break; 
       default: 
        return; 
      } 
      break; 
     } 
    } 

    CGAffineTransform rotation = CGAffineTransformMakeRotation(angle); 

    [UIView beginAnimations: @"" context: NULL]; 
    [UIView setAnimationDuration: 0.4]; 
    self.view.transform = CGAffineTransformConcat(self.view.transform, rotation); 
    [UIView commitAnimations]; 
} 

- (void) orientationDidChange: (NSNotification *) note 
{ 
    UIInterfaceOrientation orientation = [[[note userInfo] objectForKey: UIApplicationStatusBarOrientationUserInfoKey] integerValue]; 
    if ([self shouldAutorotateToInterfaceOrientation: [[UIApplication sharedApplication] statusBarOrientation]] == NO) 
     return; 

    self.view.frame = [[UIScreen mainScreen] applicationFrame]; 

    [self didRotateFromInterfaceOrientation: orientation]; 
} 

Мы используем его, загрузив этот вид контроллер, добавив его взгляд в окно, то вызов -presentModalDialog, например, так:

UIView *window = [[UIApplication sharedApplication] keyWindow]; 
[window addSubview: theController.view]; 
[theController presentDialogWindow]; 

Я собираюсь сделать простой UIViewController подкласс для реализации в скором времени, и опубликует его на моей учетной записи github. Когда я это сделаю, я отредактирую эту ссылку &.

+0

Спасибо Джим, похоже, что это будет трюк «' UIApplicationWillChangeStatusBarOrientationNotification »- это, безусловно, ключ. попробуйте, когда у меня есть запасные циклы. Я также создавал подкласс UIViewController для этого с методами '-presentPopupViewController' и' -dismissPopupViewController'. Он также уважает 'contentSizeForViewInPopo ver' в определении размера для представления. Вам придется объединиться с вашим кодом после его публикации. :-) – theory

+1

Хорошо, просто попробовал это решение. Теперь я очень хорошо убежден, что я должен делать что-то еще неправильно, потому что он не работает. Просмотрите [это видео] (http://www.youtube.com/watch?v=m_IvFAkdfuA) (22s) моего всплывающего окна, используя его. Г! – theory

Смежные вопросы