35

我有一个应用程序,我想在其中支持多个方向。我有两个要使用的 .xib 文件,myViewController.xibmyViewControllerLandscape.xib. myViewController.xib存在于 project/Resources 中,并且myViewControllerLandscape.xib存在于根项目目录中。

我想要做的是使用单独的 NIB(myViewControllerLandscape.xib)进行旋转。viewDidLoad l我尝试在ike中检测旋转:

if((self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight))
 {
  NSLog(@"Landscape detected!");
  [self initWithNibName:@"myViewControllerLandscape" bundle:nil];

 }

但我可以在 gdb 中看到,当应用程序以横向设备启动时,这不会执行。NSLog 消息不会触发。为什么是这样?我做错了什么?

此外,如果我明确地将initWithNibName函数调用放入viewDidLoad方法中,则不会加载该 nib,它会继续使用myViewController.xib文件。我的电话怎么了?我应该指定一个捆绑包吗?

谢谢!

4

5 回答 5

59

我发现了一种独立于导航控制器的更好方法。现在,我在嵌入导航控制器和未嵌入时都可以工作(虽然我现在没有使用导航控制器,所以可能有一些我没有看到的错误 - 例如,PUSH 过渡动画可能会消失好笑之类的)

两个 NIB,使用 Apple 的命名约定。我怀疑在 iOS 6 或 7 中,Apple 可能会将其添加为“功能”。我在我的应用程序中使用它,它运行良好:

  1. 触发将旋转,不应该旋转(等到旋转动画即将开始)
  2. 对横向/纵向文件使用 Apple 命名约定(如果您希望 Apple 自动加载横向版本,则 Default.png 为 Default-landscape.png)
  3. 重新加载新的 NIB
  4. 重置self.view- 这将自动更新显示
  5. 然后它会调用viewDidLoad(如果您手动重新加载 NIB,Apple 不会为您调用它)
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation) )
    {
        [[NSBundle mainBundle] loadNibNamed: [NSString stringWithFormat:@"%@-landscape", NSStringFromClass([self class])]
                                      owner: self
                                    options: nil];
        [self viewDidLoad];
    }
    else
    {
        [[NSBundle mainBundle] loadNibNamed: [NSString stringWithFormat:@"%@", NSStringFromClass([self class])]
                                      owner: self
                                    options: nil];
        [self viewDidLoad];
    }
}
于 2012-05-10T12:03:09.150 回答
40

您必须加载一个视图,然后检查方向并在需要时加载另一个视图。shouldAutorotateToInterfaceOrientation:如果要旋转,请在返回 yes 时检查方向。

我使用导航控制器来管理转换。如果我有纵向视图并且设备旋转,我会推动横向视图,然后在返回纵向时弹出横向视图。

编辑:

我对 shouldAutorotateToInterfaceOrientation: 中的所有方向都返回 YES:但是当应用程序启动时会调用它吗?你把你的观点推到这个函数里面吗?

方向常量不是您查询的全局变量,而是系统发送给控制器的消息的一部分。因此,您无法在视图控制器加载之前轻松检测方向。相反,您将应用程序硬连接到以特定方向(通常是纵向)启动,然后立即旋转。(请参阅移动版 Safari。它始终以纵向开始,然后旋转为横向。)

这是我用来交换纵向和横向视图的两种方法。

所有三个视图控制器都有这个方法:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

头像是这样的:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    if (toInterfaceOrientation==UIInterfaceOrientationLandscapeRight) {
        [self.nav pushViewController:rightLVC animated:NO];
    }
    if (toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft) {
        [self.nav pushViewController:leftLVC animated:NO];
    }
}

每个景观控制器都有这个:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    if (toInterfaceOrientation==UIInterfaceOrientationPortrait) {
        [self.nav popViewControllerAnimated:NO];
    }

该应用程序以纵向启动。如果设备的方向是横向,它会推送适当的横向。当设备旋转回纵向时,它会弹出横向。对用户来说,它看起来像是同一个视图为不同的方向重新组织自己。

于 2010-03-23T00:27:51.697 回答
5

真的很喜欢亚当的回答——我稍微修改了一下,以允许在纵向或横向中初始加载笔尖

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if( !nibNameOrNil )     nibNameOrNil = [self nibNameRotated:[[UIApplication sharedApplication] statusBarOrientation]];
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    return self;
}

- (NSString*) nibNameRotated:(UIInterfaceOrientation)orientation
{
    if( UIInterfaceOrientationIsLandscape(orientation))     return [NSString stringWithFormat:@"%@-landscape", NSStringFromClass([self class])];
    return [NSString stringWithFormat:@"%@", NSStringFromClass([self class])];
}

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    NSString *nibname = [self nibNameRotated:toInterfaceOrientation];
    [[NSBundle mainBundle] loadNibNamed:nibname owner:self options:nil];
    [self viewDidLoad];
}
于 2013-03-03T12:48:25.197 回答
1

我喜欢 TechZen 接受的答案,但正如 Adam 的评论中指出的那样,当您旋转到横向时,它会将纵向视图控制器留在导航堆栈中。这意味着在横向时点击导航栏中的后退按钮会将用户带到纵向视图。我和一位同事正在尝试从导航堆栈中手动删除额外项目的方法。它似乎有效,但我对它的经验还很少,所以我不做任何承诺。这是示例代码:

从纵向到横向:

[[self navigationController] pushViewController:landscapeViewController animated:NO];
[self removeFromNavigationStack:[MyPortraitViewController class]];

回到纵向:

[[self navigationController] pushViewController:portraitViewController animated:NO];
[self removeFromNavigationStack:[MyLandscapeViewController class]];

如果您不使用动画:NO,您可能会收到有关导航状态的警告。

帮手:

- (void)removeFromNavigationStack:(Class)oldClass {
      UINavigationController *nav = [self navigationController];
      NSMutableArray *newStack = [NSMutableArray array];
      for (UIViewController *vc in nav.viewControllers) {
          if (![vc isMemberOfClass:[oldClass class]]) {
              [newStack addObject: vc];            
          }
      [nav setViewControllers:newStack animated:NO];
  }
于 2012-03-28T23:10:55.863 回答
1

另一种选择,TPMultiLayoutViewController

于 2013-07-31T13:22:09.210 回答