【问题标题】:Support landscape for only one view in UINavigationControllerUINavigationController 中仅支持一个视图的横向
【发布时间】:2011-02-16 23:30:14
【问题描述】:

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

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

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

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

【问题讨论】:

  • 可以分享示例代码吗?

标签: ios iphone cocoa-touch uinavigationcontroller uiinterfaceorientation


【解决方案1】:

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

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

但是有一个简单的解决方案!这是一个从纵向到横向的示例。这是执行此操作的步骤,下面是支持它的代码。

  1. 创建一个“假”视图控制器,该控制器将作为子导航控制器的根。此视图控制器应支持横向。
  2. 创建UINavigationController 的新实例,将“假”视图控制器的实例添加为根,并将横向视图控制器的实例添加为第二个视图控制器
  3. 在父视图控制器中将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】:

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

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

    如果您不使用导航栏并在弹出旧控制器后推送新控制器,它应该可以工作

    【讨论】:

      【解决方案4】:

      应该像实现一样简单

      - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
      

      在每个UIViewController 中推送到您的UINavigationController。如果一个UIViewController 的视图不应该旋转,return NO 针对特定UIViewController 中的特定方向。 不过这里有个问题,如果你的 UINavigationController 实现了

      - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
      

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

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

      【讨论】:

      • 我希望它这么简单。你试过吗?有一些问题。 1.如果在手机竖屏时渲染特殊的横屏视图,当手机横屏时,视图会意外旋转为竖屏。 2.第一次渲染特殊横向视图,然后将手机旋转到纵向,然后退出特殊视图重新进入,视图意外旋转。这似乎是导航控制器的问题,我真的希望 Apple 可以让它按照你的描述工作。
      • 我试过了。我认为您遇到的问题可能特定于您的应用程序。尝试启动一个新项目以隔离 UINavigationController 旋转问题,然后运行一些实验。
      【解决方案5】:

      您可以在UINavigationController 中尝试此代码来调用当前可见视图的shouldAutorotateToInterfaceOrientation。在我的情况下,我在UITabBarController 中有UINavigationController,但您可以将其调整到其他情况。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-16
        • 2012-09-28
        • 1970-01-01
        相关资源
        最近更新 更多