Как реализовать вращение UIViewController в ответ на изменения ориентации? - PullRequest
7 голосов
/ 15 мая 2010

В моем приложении около 10 различных контроллеров UIViewController, только один из которых я хочу переключить в альбомный режим, если устройство поворачивается. (Все остальное я хочу держать в портрете.)

Чтобы реализовать ротацию в этом одном представлении, мне нужно было реализовать метод контроллера 'shouldAutorotate' и вернуть YES. Поскольку доступ к этому представлению осуществляется через контроллер навигации, мне также нужно было создать подкласс UINavigationController, который реализует shouldAutorotate и возвращает YES.

Это решение работает, но слишком хорошо. Я обнаружил, что все UIViewController, которые я нажимаю на свой подкласс UINavigationController, реагируют на ротацию, даже если я реализую 'shouldAutorotate' и возвращаю NO. (Помните: я хочу, чтобы только один конкретный UIViewController отвечал на ротацию, а не каждый в стеке контроллера навигации.)

Итак, мой вопрос: как мне лучше всего это сделать? Все решения, которые я могу придумать, кажутся 1) громоздкими и 2) хуже, похоже, не работают.

Большое спасибо.

Ответы [ 4 ]

2 голосов
/ 01 октября 2011

когда вы реализуете UINavigationController, этот класс является вашим родителем, который управляет всеми дочерними viewControllers, которые будут помещены в стек. Следовательно, RootViewController - единственный контроллер, который говорит да или нет автоповороту. Даже если вы передаете «Да» на автоповорот в контроллерах дочерних представлений, они не учитываются!

Такова природа UINavigationController. Таким образом, чтобы изменить его, у вас есть два варианта:

1- Вручную манипулируйте им, что требует от вас прохождения некоторых громоздких кодов.

2 - Измените свой дизайн, чтобы он был более совместим с UINavigationController. Это единственное представление, которое должно вращаться, должно вызываться RootViewController (а не Navigation Root View Controller - они названы одинаково, но совершенно разные), представление, в котором размещается NavController. И когда устройство вращается, оно либо выдвигает NavController к представлению, либо другому.

3- Другой метод, который также будет работать, но не рекомендуется, поскольку он нарушает концепцию MVC, заключается в том, что ваш NavController может прослушивать уведомления. Это конкретное дочернее представление, которое МОЖЕТ и ДОЛЖНО вращаться, может генерировать уведомление - например, rotateMe, и когда NavController слышит его, он вращается.

Как я уже сказал, он будет работать, но он нарушает модель MVC - что хорошо для Apple, но с точки зрения программирования не рекомендуется.

Если вам нужно дополнительное объяснение по любому из них, пожалуйста, дайте мне знать.

1 голос
/ 28 июня 2010

Я делаю это, имея контроллер корневого представления (это может быть UITabBarController) и в его методе viewDidLoad я подписываюсь на события поворота:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(didRotate:)
                                                      name:@"UIDeviceOrientationDidChangeNotification" 
                                                      object:nil];

Затем в методе didRotate: я смотрю, какой контроллер представления виден, когда произошло вращение, и в какой ориентации находится телефон:

- (void) didRotate:(NSNotification *)notification { 
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

/*
    DEVICE JUST ROTATED TO PORTRAIT MODE

 orientation == UIDeviceOrientationFaceUp ||
 orientation == UIDeviceOrientationFaceDown

 */
if(orientation == UIDeviceOrientationPortrait) {





/*
    DEVICE JUST ROTATED TO LANDSCAPE MODE
 */
}else if(orientation == UIInterfaceOrientationLandscapeLeft ||
        orientation == UIInterfaceOrientationLandscapeRight) {






}

}

Внутри этого didRotate: вы можете посмотреть, какой является видимым viewController, и делать то, что вы хотите оттуда.

Я представляю модальный контроллер вида в альбомном режиме, когда конкретный контроллер вида виден и телефон повернут в горизонтальный режим. Если какой-либо другой контроллер представления виден, я игнорирую событие.

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

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

Dave

1 голос
/ 01 сентября 2011

Возвращает YES для подкласса контроллера навигации, только если [[navController topViewController] isKindOfClass: [RotatingViewController class]]

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

Я видел примеры, использующие то, как вы это делаете, но не смог заставить его работать должным образом. Я нашел лучший способ сделать это из примеров яблок. По сути, вы реализуете presentModalViewController и создаете другое представление. UIKit выполняет базовую анимацию вращения и исчезает между представлениями. Вы должны реализовать повернутое представление как класс делегата, чтобы оно могло перезвонить своему вызывающему классу, чтобы закрыть его и обновить ориентацию.

- (void)orientationChanged:(NSNotification *)notification
{
    // We must add a delay here, otherwise we'll swap in the new view
    // too quickly and we'll get an animation glitch
    NSLog(@"orientationChanged");
    [self performSelector:@selector(updateLandscapeView) withObject:nil afterDelay:0];
}

А затем отобразить альбомный экран:

- (void)updateLandscapeView
{
PortraitView *portraitView = [[PortraitView alloc] init];
portraitView.delegate = self;
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
{
    [self presentModalViewController: portraitView animated:YES];
    isShowingLandscapeView = YES;
    }
else if (deviceOrientation == UIDeviceOrientationPortrait && isShowingLandscapeView)
{
    [self dismissModalViewControllerAnimated:YES];
    isShowingLandscapeView = NO;
    }
[portraitView release];
}
...