在UINavigationController中只支持一个视图的横向模式

13
我有一个导航控制器,其中包含几个视图控制器。我需要支持除一个特殊视图控制器外的所有视图控制器的所有方向,该特殊视图控制器仅支持横向。该特殊视图控制器出现在导航堆栈的中间。我已经进行了很多研究,但找不到任何好的解决方案。以下是我阅读和尝试过的链接。

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替换导航控制器,以显示特殊的视图控制器。 然后,我将在特殊的视图控制器中创建一个新的导航视图控制器来推送后续的视图控制器。

如果有更好的想法,请告诉我。非常感谢!

更新:我已成功使用上述方法:用presentModalViewController替换pushViewController并创建一个新的导航控制器。


你能分享一下代码示例吗? - Nam Vu
5个回答

9

每个推入导航控制器栈的视图控制器都必须支持相同的方向。这意味着不可能有一些视图控制器仅支持纵向,而其他视图控制器仅支持横向。换句话说,同一导航控制器栈上的所有视图控制器在委托中应返回相同的内容:

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

但是这个问题有一个简单的解决方案!以下是从竖屏到横屏的示例。以下是执行步骤和支持步骤的代码。
  1. 创建一个“虚拟”视图控制器,将其作为子导航控制器的根。该视图控制器应支持横向模式。
  2. 创建一个新的UINavigationController实例,将“虚拟”视图控制器作为根视图控制器,并将您的横向视图控制器作为第二个视图控制器添加进去。
  3. 从父视图控制器以modal形式展现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));
} 

最终一个直截了当的答案。 - Jeef

1

有一个私有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存在被拒绝的风险和在未来操作系统版本中出现问题的风险。请自行承担风险!

通常情况下,在大多数情况下呈现模态视图控制器是更好的解决方案。


0

实现起来应该很简单

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

在您的 UINavigationController 中推入每个 UIViewController 。 如果一个 UIViewController 的视图不应旋转,则在该特定 UIViewController 的该特定方向上返回NO
这里有一个问题,如果您的 UINavigationController 实现了...
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

它将阻止其视图控制器接收该方法。在这种情况下,您应该使用forward消息将消息转发到topViewController。

[[self topViewController] shouldAutorotateToInterfaceOrientation:interfaceOrientation];

3
我希望这件事能够如此简单。你试过吗?但这个方法存在几个问题:1. 如果你在竖屏时使用了特殊的横屏视图,当你转换到横屏时,视图会意外地旋转到竖屏模式。2. 当你第一次使用特殊的横屏视图后,将手机旋转到竖屏,然后退出该视图并重新进入,视图也会意外地旋转。这似乎是导航控制器存在的问题,我真的希望苹果公司能够使它适用于你所描述的功能。 - PokerIncome.com
我已经尝试过了。我认为你遇到的问题可能是特定于你的应用程序。尝试启动一个新项目来隔离UINavigationController旋转问题,然后进行一些实验。 - schellsan

0

您可以执行以下操作: 根据schellsan的建议更改您的代码,接下来 - 尝试将currentViewController(它将推到导航视图控制器)作为属性添加到appDelegate。在尝试推送视图控制器之前,将其设置为当前视图控制器。接下来 - 在导航控制器中创建rootViewController的子类。在此子类中重载方法

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

如果您没有使用导航栏并在弹出旧控制器后推入新控制器,则应该可以正常工作。


0
您可以在您的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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接