Переключение между несколькими представлениями с соблюдением ориентации

У меня есть приложение MVC с одной моделью и несколькими представлениями (что-то вроде скинов). Я хочу, чтобы пользователь мог переключать представления, и я не могу заставить его работать с ориентацией интерфейса. Самый простой подход выглядит так:

- (void) switchToADifferentView: (UIView*) newView {
    // self is a descendant of UIViewController
    self.view = newView;
}

Это не работает, потому что входящий вид не поворачивается в соответствии с текущей ориентацией (до следующего изменения ориентации, test случай). Есть ли способ принудительно настроить ориентацию вида? Похоже, система очень старается сохранить управление интерфейсом для себя. (Или это так же просто, как установить правильное преобразование вручную?)

Я решил, что лучше не переключать представления напрямую, а вместо этого переключать контроллеры. Это имеет смысл, так как упрощает исходный код. Но как переключать контроллеры, между которыми нет «навигационной связи»? Думаю, я мог бы использовать presentModalViewController:, но это похоже на хак. То же самое касается навигационного контроллера. Если я поменяю контроллеры вручную, я снова получу неправильную ориентацию:

- (void) switchToAController: (id) incoming {
    [currentController.view removeFromSuperview];
    [window addSubview:incoming.view]; // does not respect current orientation
}

Теперь как, черт возьми, мне просто заменить текущий контроллер на другой? Опять же, контроллеры — это что-то вроде «скинов», работающих над общей моделью, поэтому на самом деле нет смысла притворяться, что скин A — это «модальный» диалог поверх скина B или что они являются частью стека навигации.


person zoul    schedule 13.05.2010    source источник


Ответы (2)


При переключении представлений напрямую с помощью первого примера кода ориентацию можно исправить, установив преобразование вручную:

- (CGAffineTransform) transformForOrientation: (UIInterfaceOrientation) io
{
    NSParameterAssert(io <= 4);
    // unknown, portrait, portrait u/d, landscape L, landscape R
    float angles[] = {0, 0, M_PI, M_PI/2, -M_PI/2};
    return CGAffineTransformMakeRotation(angles[io]);
}

- (void) switchToView: (UIView*) newView
{
    newView.transform = [self transformForOrientation:self.interfaceOrientation];
    self.view = newView;
}

Кроме того, если вы хотите обмениваться видами во время вращения, все становится еще сложнее. Сначала вы должны преобразовать входящий вид в соответствии с текущим. Это нужно сделать в обратном вызове willRotate…:

- (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation) target
         duration: (NSTimeInterval) duration
{
    incomingView = [[UIView alloc] init…];
    incomingView.transform = self.view.transform;
}

Затем вы переключаете представления в обратном вызове willAnimate… и устанавливаете преобразование в соответствии с целевой ориентацией:

- (void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation) io
         duration: (NSTimeInterval) duration
{
    incomingView.transform = [self transformForOrientation:io];
    self.view = incomingView;
}

Таким образом, новый вид заменяет текущий и плавно поворачивается в целевое положение.

person zoul    schedule 13.05.2010
comment
Есть ли какие-либо справочные документы о необходимости вручную преобразовать ориентацию вида? - person Teo Choong Ping; 31.08.2010

В конце концов я пошел с «батутным» подходом. Каждый «скин» — это отдельный контроллер, и есть специальный корневой контроллер, который представляет скины как модальные контроллеры. Когда скин хочет переключиться на другой, он устанавливает флажок, указывающий желаемый следующий скин, и закрывает себя. Корневой контроллер просыпается (viewWillAppear), замечает флаг и отображает следующий скин.

Это решение имеет два основных преимущества: 1] Код контроллера остается простым, так как каждый контроллер отображает только один вид, без переключения вида. 2] Нет необходимости взламывать код ориентации, потому что ориентация представления внутри модально отображаемых контроллеров прозрачно обрабатывается системой.

person zoul    schedule 14.05.2010