Переключайтесь между несколькими видами, соблюдая ориентацию - PullRequest
1 голос
/ 13 мая 2010

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

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

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

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

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

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

Ответы [ 2 ]

1 голос
/ 13 мая 2010

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

- (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;
}

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

0 голосов
/ 14 мая 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...