Подтвердить что ты не робот

Методы вращения UIViewController

Какой объект несет ответственность за прохождение вызовов метода вращения UIViewController, т.е.

  • shouldAutorotateToInterfaceOrientation:
  • willRotateToInterfaceOrientation:duration:
  • willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
  • willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
  • didRotateFromInterfaceOrientation:

Я предполагаю, что это UIApplication (но, возможно, AppDelegate или UIWindow).

Следующий вопрос: каким образом объект знает, с кем UIViewController разговаривать?

Как он узнает, что UIViewController имеет свое представление в качестве подвид окна?

Есть ли сообщение, которое вы можете отправить, или свойство, которое вы можете установить (какого-либо объекта), который устанавливает "Active" UIViewController для приложения?

4b9b3361

Ответ 1

Кажется, что UIApplication отправляет сообщение активному контроллеру представления.

Но как ваш экземпляр View Controller получает эти сообщения?

Сообщение пересылается на первый контроллер представления, представление которого было добавлено в экземпляр UIWindow.

Это сводится к 3 основным сценариям:

  • ViewController, представление которого добавляется непосредственно в UIWindow экземпляр (приложение с одним представлением)

  • Контроллер навигации в   Навигационное приложение, затем   контроллер навигации пересылает   сообщение в представление активных просмотров   контроллер.

  • Контроллер панели вкладок в панели вкладок       приложение, затем панель вкладок       контроллер пересылает сообщение       активный контроллер представления представлений (или       активный контроллер навигации).

Проблема, которую вы будете иметь, заключается в том, что вы создаете приложение с несколькими представлениями, но НЕ используйте контроллер навигации или контроллер панели вкладок. Если вы вручную конвертируете представления в и из экземпляра UIWindow, вы не будете надежно получать эти сообщения. Это похоже на сообщения вроде этого: iPhone viewWillAppear не стреляет

Просто используйте соглашения Apple для нескольких просмотров, и все будет в порядке. Надеюсь, это экономит один час или два.

Ответ 2

Это все волшебство, о котором вы никогда не беспокоитесь. Просто добавьте свой корневой вид контроллера в окно - или получите панель вкладок или контроллер навигации, чтобы сделать это для вас, - и он получит эти сообщения.

(Но если вы соскучитесь с отладчиком, вы можете прийти к тому же выводу, что и я: там есть какая-то внутренняя таблица, отображающая каждый вид контроллера обратно на контроллер, и сообщения отправляются на основе этой ссылки.)


Обновление: Это было действительно частное волшебство в 2009 году, когда я впервые написал этот ответ, но последующие изменения в iOS сделали API-интерфейсы за ним общедоступными. Теперь контроллер корневого представления доступен через свойство UIWindow.rootViewController, а дерево контроллеров представления потомков формируется с использованием свойства UIViewController.childViewControllers.

Контроллеры родительского контроля несут ответственность за уведомление своих детей о изменениях ориентации. (Я не знаю, как будет уведомлен контроллер корневого представления, но вы можете установить точку останова и узнать сами.) Метод -shouldAutomaticallyForwardRotationMethods решает, сделает ли UIViewController это для вас. Если он возвращает NO, вы станете ответственным за это в своих методах -willRotateToInterfaceOrientation:duration:, -willAnimateRotationToInterfaceOrientation:duration: и -didRotateFromInterfaceOrientation:.

Ответ 3

Как он знает, какой UIViewController имеет свое представление в качестве подвид окна?

Класс UIViewController поддерживает статическую карту между представлениями и их контроллерами представлений. Эта карта запрашивается в нескольких ключевых местах внутри CocoaTouch. В частности, [UIView nextResponder] запрашивает его и возвращает контроллер, если найден.

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

Ответ 4

У меня есть аналогичная проблема.

У меня есть игра, работающая в альбомной ориентации (как в левом, так и в правом ландшафте).

Для управления многозадачным приложением я использую корневой UIviewController, т.е. фиктивный UIViewcontroller с UIview, который ничего не делает. Затем я добавляю в него все другие UIview как подвью.

При запуске приложения эмулятор быстро поворачивается на портретную ориентацию, и я получаю каждый из своих представлений с его кадровым свойством, похожим на (0, -80,320,480). Это приводит к тому, что изображение сжимается прямоугольником 160 X 320 с правой стороны.

Я заметил, что метод toAsutorotateToInterfaceOrientation: для каждого subview вызывается только один раз, и это происходит, когда он добавляется в корневой вид. Позже, при вращении устройства, только корневой вид получает его метод.

Неудивительно, что любой из вызовов методов - willAnimate * методов отправляется только в корневое представление, поэтому определение любого из этих методов в подзаголовках бессмысленно.

Эти методы вызывается каждый раз, когда ориентация изменяется на ориентацию, принятую методом - shouldAutorotateToInterfaceOrientation:. поэтому я решил, что я могу chaage мое свойство рамки subviews оттуда.

Для этого я определил следующий метод в моем классе rootViewController:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
    subview1_ViewController.view.frame = CGRectMake(0,0,480,320);
    subview2_ViewController.view.frame = CGRectMake(0,0,480,320);
        ...
}

Я не понимаю, почему свойство frame не обновляется, но я знаю, что это обходное решение работает.

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