Xcode 4.5和iOS 6.x中的故事板方向支持?

问题描述:

我创建了两个相同的故事板,除了一个包含纵向视图,另一个包含横向视图。Xcode 4.5和iOS 6.x中的故事板方向支持?

我不想使用自动调整大小的遮罩,因为一些视图的布局在纵向和横向之间完全改变。我手动移动视图控件上的代码在过去,但我是一个更简单的方法在此时间后:)

我发现的最接近的解决方案是从“benyboariu” - Storyboards orientation support for xCode 4.2?

下面的代码我使用的是在iOS 5.x上正常工作,但不在iOS 6.x上正常工作。

- (void)updateLandscapeView 
{ 
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation; 

if (deviceOrientation == UIDeviceOrientationUnknown) 
{ 
    if ([[UIScreen mainScreen] bounds].size.height > [[UIScreen mainScreen] bounds].size.width) 
    { 
     deviceOrientation = UIDeviceOrientationPortrait; 
     self.appDelegate.isShowingLandscapeView = NO; 
    } 
    else 
    { 
     deviceOrientation = UIDeviceOrientationLandscapeLeft; 
     self.appDelegate.isShowingLandscapeView = YES; 
    } 
} 

if (UIDeviceOrientationIsLandscape(deviceOrientation) && !self.appDelegate.isShowingLandscapeView) 
{ 
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard-Landscape" bundle:[NSBundle mainBundle]]; 
    UIViewController * landscape = [storyboard instantiateViewControllerWithIdentifier:@"RootViewController-Landscape"]; 
    self.appDelegate.isShowingLandscapeView = YES; 
    [UIView transitionWithView:landscape.view duration:0 options:UIViewAnimationOptionTransitionCrossDissolve|UIViewAnimationCurveEaseIn animations:^{ 
     self.view = landscape.view; 
    } completion:NULL]; 
} 
else if (UIDeviceOrientationIsPortrait(deviceOrientation) && self.appDelegate.isShowingLandscapeView) 
{ 
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard-Portrait" bundle:[NSBundle mainBundle]]; 
    UIViewController * portrait = [storyboard instantiateViewControllerWithIdentifier:@"RootViewController"]; 
    self.appDelegate.isShowingLandscapeView = NO; 
    [UIView transitionWithView:portrait.view duration:0 options:UIViewAnimationOptionTransitionCrossDissolve|UIViewAnimationCurveEaseIn animations:^{ 
     self.view = portrait.view; 
    } completion:NULL]; 
} 
} 

在iOS 6.x的调试时,我得到的错误是:

终止应用程序由于未捕获的异常“UIViewControllerHierarchyInconsistency”,理由是:“视图只能与最多关联一次一个视图控制器!查看UIView:0x108276b0; frame =(0 0; 568 268); autoresize = RM + BM;动画= {position = CABasicAnimation:0x10815c60; bounds = CABasicAnimation:0x1082a5e0; }; layer = CALayer:0x10827710与RootViewController:0x10821f10相关联。在将此视图与RootViewController关联之前清除此关联:0x961a150。

我通常将视图控制器与NIB断开,以解决这种错误,但无法通过故事板进行拼接。

任何人有任何想法?

那么,尝试各种方法来尝试和解决这个问题后,我想出了这个解决方案,它适用于iOS 5.x和6.x.

基本上,这个问题似乎是因为导航控制器,这样,而不是做

self.view = landscape.view; 

self.view = portrait.view; 

需要更换所有包含在导航控制器的视图控制器叠加。

我在下面的代码中做的是在导航控制器堆栈中创建所有视图控制器的NSMutableArray。然后循环每个视图控制器并获取视图标记以确定哪个视图需要替换。然后,我简单地使用横向或纵向版本替换视图控制器,然后将导航控制器视图控制器阵列设置为修改后的阵列,从而替换所有视图控制器。

if (UIDeviceOrientationIsLandscape(deviceOrientation) && !self.appDelegate.isShowingLandscapeView) 
{ 
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard-Landscape" bundle:[NSBundle mainBundle]]; 
    SearchViewController * landscape = [storyboard instantiateViewControllerWithIdentifier:@"SearchViewController-Landscape"]; 
    self.appDelegate.isShowingLandscapeView = YES; 
    [UIView transitionWithView:landscape.view duration:0 options:UIViewAnimationOptionTransitionCrossDissolve|UIViewAnimationCurveEaseIn animations:^{ 
     NSMutableArray * viewControllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]]; 
     if (viewControllers && [viewControllers count] > 0) 
     { 
      for (NSUInteger index = 0; index < [viewControllers count]; index++) 
      { 
       if ([[[viewControllers objectAtIndex:index] view] tag] == 1000) 
       { 
        RootViewController * root = [storyboard instantiateViewControllerWithIdentifier:@"RootViewController-Landscape"]; 
        [viewControllers replaceObjectAtIndex:index withObject:root]; 
       } 
       else if ([[[viewControllers objectAtIndex:index] view] tag] == 2000) 
       { 
        [viewControllers replaceObjectAtIndex:index withObject:landscape]; 
       } 
      } 

      [self.navigationController setViewControllers:viewControllers]; 
     } 
    } completion:NULL]; 
} 
else if (UIDeviceOrientationIsPortrait(deviceOrientation) && self.appDelegate.isShowingLandscapeView) 
{ 
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard-Portrait" bundle:[NSBundle mainBundle]]; 
    SearchViewController * portrait = [storyboard instantiateViewControllerWithIdentifier:@"SearchViewController"]; 
    self.appDelegate.isShowingLandscapeView = NO; 
    [UIView transitionWithView:portrait.view duration:0 options:UIViewAnimationOptionTransitionCrossDissolve|UIViewAnimationCurveEaseIn animations:^{ 
     NSMutableArray * viewControllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]]; 
     if (viewControllers && [viewControllers count] > 0) 
     { 
      for (NSUInteger index = 0; index < [viewControllers count]; index++) 
      { 
       if ([[[viewControllers objectAtIndex:index] view] tag] == 1000) 
       { 
        RootViewController * root = [storyboard instantiateViewControllerWithIdentifier:@"RootViewController"]; 
        [viewControllers replaceObjectAtIndex:index withObject:root]; 
       } 
       else if ([[[viewControllers objectAtIndex:index] view] tag] == 2000) 
       { 
        [viewControllers replaceObjectAtIndex:index withObject:portrait]; 
       } 
      } 

      [self.navigationController setViewControllers:viewControllers]; 
     } 
    } completion:NULL]; 
} 

我已经扩展了代码以展示如何在导航控制器中使用嵌套视图。如果你正在使用根视图控制器,那么显然不需要遍历所有视图控制器,只需替换索引为0的视图控制器。

希望这可以帮助某人!

+0

嗨,你对1000和2000是什么? – Jules

将您的portait视图控制器更改为普通视图(将其从视图控制器中取出)。现在你应该能够将它实例化为一个UIView,并进行转换,而不必担心它与多个视图控制器相关联。

+0

我已经尝试从故事板中的控制器中删除UIView,但它看起来像你只能有控制器在那里,即你需要一个UIViewController不是一个UIView,或一个UITableViewController不是一个UITableView等。 –