2013-07-02 34 views
2

我需要为纵向和横向使用不同的xib文件。我没有使用自动布局,但我使用的是iOS6。 (见my previous question如果你在乎为什么。)在iOS6下旋转多个xibs的问题

我跟随亚当的回答this question用amergin的initWithNib名字把戏修改,用我自己的iPhone/iPad需要修改。这里是我的代码:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{  
    [[NSBundle mainBundle] loadNibNamed:[self xibNameForDeviceAndRotation:toInterfaceOrientation] 
            owner: self 
           options: nil]; 
    [self viewDidLoad]; 
} 

- (NSString *) xibNameForDeviceAndRotation:(UIInterfaceOrientation)toInterfaceOrientation 
{ 
    NSString *xibName ; 
    NSString *deviceName ; 

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 
     deviceName = @"iPad"; 
    } else { 
     deviceName = @"iPhone"; 
    } 

    if(UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) 
    { 
     xibName = [NSString stringWithFormat:@"%@-Landscape", NSStringFromClass([self class])]; 
     if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) { 
      return xibName; 
     } else { 
      xibName = [NSString stringWithFormat:@"%@_%@-Landscape", NSStringFromClass([self class]), deviceName]; 
      if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) { 
       return xibName; 
      } else { 
       NSAssert(FALSE, @"Missing xib"); 
       return nil; 
      } 
     } 

    } else { 
     xibName = [NSString stringWithFormat:@"%@", NSStringFromClass([self class])]; 
     if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) { 
      return xibName; 
     } else { 
      xibName = [NSString stringWithFormat:@"%@_%@", NSStringFromClass([self class]), deviceName]; 
      if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) { 
       return xibName; 
      } else { 
       NSAssert(FALSE, @"Missing xib"); 
       return nil; 
      } 
     } 
    } 
} 

,当然我做:

- (BOOL) shouldAutorotate 
{ 
    return YES; 
} 

- (NSUInteger)supportedInterfaceOrientations { 
    return UIInterfaceOrientationMaskAll; 
} 
在我的视图控制器

和:

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window 
{ 
    return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown); 
} 

在我的委托。

我有两个可能相关的问题。首先,简单的一个。我不旋转颠倒。我已经在xcode中为iPad和iPhone开启了所有适当的位。这可能是一个单独的问题,也可能是我的问题的核心。

真正的问题是,当我旋转到横向模式时,我的xib被替换,但视图关闭了90度。

这是我的2 xib的样子。 (我已经有色他们华丽地,所以你可以看到,他们是不同的。)

enter image description hereenter image description here

,你可以看到,当我(在风景模式最初)运行它的景观厦门国际银行是正确的。

enter image description here

当我旋转为纵向,也正确

enter image description here

但是当我转回到景观厦门国际银行被替换,但认为是关闭的90度。

enter image description here

这里有什么错?

+0

我想你是加载到早期的xib,你是否尝试将代码从'willRotatetToInterface..'移动到'didRotateFrom ...'中? – danypata

+0

嗯,这给了我从方向。由于基本上只有2个可能的我的应用程序,我猜这是好的,但它似乎不干净...... –

+0

,它也行不通。洋红色现在是全宽,但UI小部件仍然偏离90度。 –

回答

0

我在这里回答我的问题,从我的博客的iOS完整的文章粘贴在http://www.notthepainter.com/topologically-challenged-ui/

我一位朋友帮助我,他用IBOutlets在一个xib文件中使用2个视图进行纵向和横向视图,并在设备旋转之间切换它们。完美,对吧?那么,不,如果您在XIB中有2个视图,则无法将您的IBOutlet连接到这两个位置。我有它的视觉工作,但我的控制只在一个方向工作。

我终于想出了使用定向主视图控制器的想法,该控制器在设备旋转时加载容器视图控制器。这工作得很好。让我们看一下代码:如果你读的容器视图控制器我以前的博客条目

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration 
{ 
    if (_timerViewController) { 
     [_timerViewController.view removeFromSuperview]; 
     [_timerViewController willMoveToParentViewController:nil]; 
     [_timerViewController removeFromParentViewController]; 
     self.timerViewController = nil; 
    } 

    self.timerViewController = [[XTMViewController alloc] initWithNibName: 
      [self xibNameForDeviceAndRotation:interfaceOrientation withClass:[XTMViewController class]] 
              bundle:nil]; 

    // use bounds not frame since frame doesn't take the status bar into account 
    _timerViewController.view.frame = _timerViewController.view.bounds = self.view.bounds; 

    [self addChildViewController:_timerViewController]; 
    [_timerViewController didMoveToParentViewController:self]; 
    [self.view addSubview: _timerViewController.view]; 
} 

的addChildViewController和didMoveToParentViewController应该很熟悉。尽管如此,还是有两件事要注意。我会先处理第二个,我设置子视图控制器的框架和界限,而不是框架。这是考虑到状态栏。

并注意到调用xibNameForDeviceAndRotation从它的xib文件加载视图控制器。让我们看看该代码:

- (NSString *) xibNameForDeviceAndRotation:(UIInterfaceOrientation)toInterfaceOrientation withClass:(Class) class; 
{ 
    NSString *xibName ; 
    NSString *deviceName ; 

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 
     deviceName = @"iPad"; 
    } else { 
     deviceName = @"iPhone"; 
    } 

    if(UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { 
     xibName = [NSString stringWithFormat:@"%@-Landscape", NSStringFromClass(class)]; 
     if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) { 
      return xibName; 
     } else { 
      xibName = [NSString stringWithFormat:@"%@_%@-Landscape", NSStringFromClass(class), deviceName]; 
      if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) { 
       return xibName; 
      } else { 
       NSAssert(FALSE, @"Missing xib"); 
       return nil; 
      } 
     } 
    } else { 
     xibName = [NSString stringWithFormat:@"%@", NSStringFromClass(class)]; 
     if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) { 
      return xibName; 
     } else { 
      xibName = [NSString stringWithFormat:@"%@_%@", NSStringFromClass(class), deviceName]; 
      if([[NSBundle mainBundle] pathForResource:xibName ofType:@"nib"] != nil) { 
       return xibName; 
      } else { 
       NSAssert(FALSE, @"Missing xib"); 
       return nil; 
      } 
     } 
    } 
    return nil; 
} 

这里有很多事情要做。我们来回顾一下。我首先确定你是在iPhone还是在iPad上。 xib文件的名称中会包含iPhone或iPad。接下来我们检查一下,看看我们是否处于横向模式。如果是的话,我们从类名建立一个测试字符串,通过NSStringFromClass使用类反射。接下来,我们使用pathForResource来检查xib是否存在于我们的包中。如果有,我们返回xib名称。如果没有,我们再次尝试将设备名称放入xib名称中。如果存在则返回,如果不存在则声明失败。肖像是相似的,除了按照惯例,我们不把“-Portrait”放入xib名称中。

这段代码足够有用,足够通用,我将它放在我的EnkiUtils开源项目中。

由于这是iOS6的,我们需要把在iOS6的旋转样板代码:

- (BOOL) shouldAutorotate 
{ 
    return YES; 
} 

- (NSUInteger)supportedInterfaceOrientations { 
    return UIInterfaceOrientationMaskAll; 
} 

奇怪的是,我们还需要手动调用willAnimateRotationToInterfaceOrientation在iPad上。 iPhone会自动获取willAnimateRotationToInterfaceOrientation,但iPad不会。

- (void) viewDidAppear:(BOOL)animated 
{ 
    // iPad's don't send a willAnimate on launch... 
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 
     [self willAnimateRotationToInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation] duration:0]; 
    } 
} 

那么,我们完成了吗?尴尬没有。你看,当我编写XTMViewController类时,我打破了模型 - 视图 - 控制器的设计模式!这很容易实现,Apple已经通过将View和Controller放入同一个类中来帮助我们。在VC的.h文件中不经意地混入模型数据是非常容易的。我完成了这一切。当我运行上述代码时,它的功能非常出色,我可以整天旋转它,并且UI在两个方向都是正确的。但是当我的运动计时器正在运行时,我旋转设备时发生了什么?是的,他们全部被删除,用户界面重置为初始状态。这根本不是我想要的!

我做了一个XTMUser类来保存所有的时间数据,我把所有的NSTimers放到XTMOrientationMasterViewController类中,然后我创建了一个协议,以便XTMOrientationMasterViewController可以响应XTMViewController类中的UI抽头。

然后我完成了。

0

这是我如何做到这一点,它适用于iOS 5+:

- (void)viewDidLoad { 
    [[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(checkBagRotation) 
              name:UIApplicationDidChangeStatusBarOrientationNotification 
              object:nil]; 
    [self checkBagRotation]; 
} 

- (void)checkBagRotation { 
    orientation = [UIApplication sharedApplication].statusBarOrientation; 
    if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) { 
     [[NSBundle mainBundle] loadNibNamed:@"Controller-landscape" 
             owner:self 
            options:nil]; 
    } else { 
     [[NSBundle mainBundle] loadNibNamed:@"Controller-portrait" 
             owner:self 
            options:nil]; 

} 
+0

我会给你一个机会,我会认为代理方法会起作用,我敢肯定我的代码在iOS5下工作... –

+0

nope,不适合我... –

1

我一直在追随Paul Cezanne去年所走过的路。不知道他是否尝试过这种方法,但是我通过将根控制器设置为导航控制器而不是我的视图控制器类来解决了原始问题(在此问题中提到)。由于我使用的是“空项目”模板和XIB文件,这意味着改变了正常:

self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; 
self.window.rootViewController = self.viewController; 

内AppDelegate.m,这反而:

self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; 
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; 
navigationController.navigationBar.hidden = YES; 
self.window.rootViewController = navigationController; 
是,我只是创建了

一个通用的UINavigationController并将其设置为根视图控制器。

我不确定这是否会导致其他问题,并且可能有办法弄清楚(也许您将需要源代码,但是)UINavigationController所做的事情并不是UIViewController所做的。可以像在正确的地方一个额外的setNeedsLayout类型的调用一样简单。如果我弄明白了,我会为未来的读者编辑这个答案。

幸得萨克蒂对Easiest way to support multiple orientations? How do I load a custom NIB when the application is in Landscape?意见,我不应该忽略我第一次阅读:

我加入了视图控制器导航控制器,并提出其 这使得按预期

它的工作

编辑:添加额外的行到示例代码来隐藏导航栏,因为大多数人在这个问题后不会想这样做。

+0

有趣的应用程序蟑螂。如果它适合我​​,它会简单得多。当然,这个特定的项目很长时间,但我可能会再次打开它来尝试。我会高兴,因为它很聪明,不知道它是否会起作用。谢谢! –