Методы вращения UIViewController
Какой объект несет ответственность за прохождение вызовов метода вращения UIViewController
, т.е.
-
shouldAutorotateToInterfaceOrientation:
-
willRotateToInterfaceOrientation:duration:
-
willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
-
willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
-
didRotateFromInterfaceOrientation:
Я предполагаю, что это UIApplication
(но, возможно, AppDelegate или UIWindow).
Следующий вопрос: каким образом объект знает, с кем UIViewController
разговаривать?
Как он узнает, что UIViewController
имеет свое представление в качестве подвид окна?
Есть ли сообщение, которое вы можете отправить, или свойство, которое вы можете установить (какого-либо объекта), который устанавливает "Active" UIViewController
для приложения?
Ответы
Ответ 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 не обновляется, но я знаю, что это обходное решение работает.
Надеюсь, это поможет...