Поддержка ландшафта только для одного вида в UINavigationController

У меня есть контроллер навигации, у которого есть несколько контроллеров представления. Мне нужно поддерживать все ориентации для всех контроллеров представлений, кроме одного специального контроллера, который поддерживает только ландшафт. Этот специальный контроллер просмотра отображается в середине стека навигации. Я провел довольно много исследований, но не нашел хорошего решения. Вот ссылки, которые я прочитал и попробовал.

http://www.iphonedevsdk.com/forum/iphone-sdk-development/3219-force-landscape-mode-one-view.html#post60435

Как повернуть экран в альбомную?

Как авторотировать из портретного в альбомный режим?  iPhone - разрешить ландшафтную ориентацию только на одном контроллере просмотра  http://goodliffe.blogspot.com/2009/12/iphone-forcing-uiview-to-reorientate.html

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

Если у кого-то есть лучшая идея, пожалуйста, дайте мне знать. Действительно оценен!

UPDATE: Я успешно использовал описанный выше метод: замените pushViewController на presentModalViewController и создайте новый контроллер навигации.

Ответ 1

Каждый контроллер представлений, вставленный в стек навигационных контроллеров, должен поддерживать одинаковые ориентации. Это означает, что некоторые контроллеры представлений не могут поддерживать только портрет, а другие поддерживают только пейзаж. Другими словами, все диспетчеры представлений в одном стеке контроллера навигации должны возвращать то же самое в делегате:

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

Но это простое решение! Вот пример перехода от портрета к пейзажу. Вот шаги, чтобы сделать это, а ниже - код для его поддержки.

  • Создайте "фальшивый контроллер представлений", который будет root в контроллере суб-навигации. Этот контроллер просмотра должен поддерживать ландшафт.
  • Создайте новый экземпляр UINavigationController, добавьте экземпляр "fake view controller" в качестве пользователя root и экземпляр вашего контроллера ландшафтного представления в качестве второго контроллера представления.
  • Представить экземпляр UINavigationController как модальный из родительского контроллера представления

Сначала создайте новый контроллер представления (FakeRootViewController) с помощью этого кода:

@interface FakeRootViewController : UIViewController
@property (strong, nonatomic) UINavigationController* parentNavigationController;
@end

@implementation FaceRootViewController
@synthesize parentNavigationController;
// viewWillAppear is called when we touch the back button on the navigation bar
(void)viewWillAppear:(BOOL)animated {
  // Remove our self from modal view though the parent view controller
  [parentNavigationController dismissModalViewControllerAnimated:YES];
}
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
   return (interfaceOrientation == UIInterfaceOrientationIsLandscape(interfaceOrientation));
} 

Вот код для представления контроллера вида, который вы хотите показать в ландшафтном режиме:

FakeRootViewController* fakeRootViewController = [[FakeRootViewController alloc] init];[fakeRootViewController.navigationItem setBackBarButtonItem:backButton]; // Set back button
// The parent navigation controller is the one containing the view controllers in portrait mode.
fakeRootViewController.parentNavigationController = parentNavigationController;

UINavigationController* subNavigationController = // Initialize this the same way you have initialized your parent navigation controller.

UIViewController* landscapeViewController = // Initialize the landscape view controller

[subNavigationController setViewControllers:
   [NSArray arrayWithObjects:fakeRootViewController, 
                                               landscapeViewController, nil] animated:NO];

[_navigationController presentModalViewController:subNavigationController animated:YES];

Помните, что LandscapeViewController также должен иметь эту реализацию:

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
   return (interfaceOrientation == UIInterfaceOrientationIsLandscape(interfaceOrientation));
} 

Ответ 2

Там есть частный API для изменения ориентации. Поместите в свой толкаемый контроллер вида -viewWillAppear::

if ([UIDevice instancesRespondToSelector:@selector(setOrientation:)]) {
    [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}

Чтобы подавить предупреждение компилятора, добавьте его в файл .m вашего контроллера:

@interface UIDevice()
- (void)setOrientation:(UIDeviceOrientation)orientation; // private API to let POIEntryVC be pushed over landscape route view
@end

Как всегда, существует риск отклонения и риск взлома в будущих версиях ОС при использовании частных API. Сделайте на свой страх и риск!

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

Ответ 3

Это должно быть так же просто, как реализовать

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

в каждом UIViewController, введенном в ваш UINavigationController. В случае, если один UIViewController вид не должен вращаться, return NO для этой конкретной ориентации в этом конкретном UIViewController. Здесь есть, но если UINavigationController реализует

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

он заблокирует свой viewControllers от получения этого метода. В этом случае вы должны отправить сообщение в topViewController с помощью

[[self topViewController] shouldAutorotateToInterfaceOrientation:interfaceOrientation];

Ответ 4

Вы можете попробовать этот код в своем UINavigationController, чтобы вызвать текущий видимый вид shouldAutorotateToInterfaceOrientation. В моем случае у меня есть UINavigationController в UITabBarController, но вы, вероятно, можете адаптировать его к другим случаям.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if ([appDelegate.tabBarController.selectedViewController respondsToSelector:@selector(topViewController)])
    {
        UINavigationController *nc = (UINavigationController*)appDelegate.tabBarController.selectedViewController;
        return [nc.topViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
    }
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

Ответ 5

Вы можете делать действия: Измените свой код в соответствии с предложением Шеллсана, затем - Попробуйте добавить currentViewController (который будет нажимать на navigation viewController) как свойство appDelegate. Когда вы пытаетесь нажать контроллер просмотра, перед этим установите его в контроллер текущего вида. Далее - создайте подкласс rootViewController в контроллере навигации. В этом методе owerload подкласса

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Overriden to allow any orientation.
    return [appDelegate.currentViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

Он должен работать, если вы не используете панель навигации и не нажимаете новый контроллер после появления старого