在UINavigationController中仅支持一个视图的格局

时间:2011-02-16 23:30:14

标签: ios iphone cocoa-touch uinavigationcontroller uiinterfaceorientation

我有一个导航控制器,它有几个视图控制器。除了一个只支持横向的特殊视图控制器外,我需要支持所有视图控制器的所有方向。此特殊视图控制器显示在导航堆栈的中间。我做了很多研究,但找不到任何好的解决方案。以下是我阅读和尝试过的链接。

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

How to rotate screen to landscape?

How to autorotate from portrait to landscape mode?  iPhone - allow landscape orientation on just one viewcontroller  http://goodliffe.blogspot.com/2009/12/iphone-forcing-uiview-to-reorientate.html

接下来,我将尝试用presentModalViewController替换导航控制器,以显示特殊视图控制器。然后我将在特殊视图控制器内创建一个新的导航视图控制器来推送后续的视图控制器。

如果有人有更好的主意,请告诉我。真的很感激!

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

5 个答案:

答案 0 :(得分:9)

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

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

但是有一个简单的解决方案!这是一个从肖像到风景的例子。以下是执行此操作的步骤,以下是支持它的代码。

  1. 创建一个'假'视图控制器,它将作为子导航控制器的根目录。此视图控制器应支持格局。
  2. 创建UINavigationController的新实例,以root身份添加'假'视图控制器的实例,并将横向视图控制器的实例添加为第二视图控制器
  3. 从父视图控制器
  4. 呈现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));
    } 
    

答案 1 :(得分: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时,存在被拒绝的风险以及未来操作系统版本中存在破坏的风险。请自担风险!

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

答案 2 :(得分:0)

应该像实施

一样简单
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
每个UIViewController中的

都会被推入UINavigationController。如果一个UIViewController的视图不应该针对特定return NO中的特定方向UIViewController进行轮播。 如果你的UINavigationController实现了

,那么这里有一个问题
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

它将阻止其viewControllers接收该方法。在这种情况下,您应该使用

将消息转发到topViewController
[[self topViewController] shouldAutorotateToInterfaceOrientation:interfaceOrientation];

答案 3 :(得分: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);
}

答案 4 :(得分:0)

你可以采取行动: 根据schellsan建议更改您的代码,接下来 - 尝试将currentViewController(将推送到导航viewController)添加为appDelegate的属性。当您尝试推送视图控制器时,请在此之前将其设置为当前视图控制器。接下来 - 在导航控制器中创建rootViewController的子类。在这个子类中的owerload方法

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

如果您没有使用导航栏并在弹出旧的

后推送新的控制器,它应该有效