在iOS6下多个xib旋转的问题

我需要为纵向和横向使用不同的xib文件。 我没有使用自动布局,但我使用iOS6。 (见我以前的问题,如果你在乎为什么。)

我跟随亚当的回答这个问题修改与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被replace,但视图closures了90度。

这是我的2个xib的样子。 (我把它们涂成了花色,所以你可以看到它们是不同的。)

在这里输入图像说明在这里输入图像说明

你可以看到当我运行它(最初在风景模式)景观xib是正确的。

在这里输入图像说明

当我旋转到肖像,这也是正确的

在这里输入图像说明

但是当我旋转回到风景时,xib被replace,但视图closures了90度。

在这里输入图像说明

这里有什么问题?

我一直在追随保罗·塞尚(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; 

也就是说,我只是创build了一个通用的UINavigationController并将其设置为根视图控制器。

我不知道这是否会导致其他问题,并有可能找出一种方法(也许你会需要源代码,虽然)UINavigationController所做的UIViewController不。 可以像在正确的地方一个额外的setNeedsLayouttypes的调用一样简单。 如果我弄明白了,我会为未来的读者编辑这个答案。

信用去Sakti的评论最简单的方法来支持多个方向? 如何在应用程序处于横向模式时加载自定义的NIB? 这是我第一次读它们时不应该忽略的:

我添加了视图控制器到导航控制器,并提出它使其按预期工作

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

这是我如何做的,它适用于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]; } 

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

我有一个朋友帮助我,他用一个xib文件中的2个视图与IBOutlets纵向和横向视图,他在他们之间切换设备旋转。 完美,对吧? 那么,不,如果您在XIB中有两个视图,则无法将您的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]; } 

如果您阅读我以前在Container View Controller上的博客条目,则应该熟悉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。 接下来我们检查一下,看看我们是否处于横向模式。 如果是的话,我们从类名build立一个testingstring,通过NSStringFromClass使用类reflection。 接下来,我们使用pathForResource来检查xib是否存在于我们的bundle中。 如果是这样,我们返回xib名称。 如果没有,我们再次尝试将设备名称放入xib名称中。 如果存在则返回,如果不存在则声明失败。 肖像是相似的,除了按照惯例,我们不把“-Portrait”放入xib名称。

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

由于这是iOS6,我们需要放入iOS6旋转样板代码:

 - (BOOL) shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } 

奇怪的是,我们还需要在iPad上手动调用willAnimateRotationToInterfaceOrientation。 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类,我打破了模型,视图,控制器的devise模式! 这很容易做到,苹果公司已经帮助我们把视图和控制器放在同一个class上。 在VC的.h文件中不经意地混入模型数据是非常容易的。 而我完成了这一切。 当我运行上面的代码,它出色地工作,我可以整天旋转,并在两个方向的用户界面是正确的。 但是当我的运动计时器正在运行时,当我旋转设备时,您会怎么想呢? 是的,他们都被删除,用户界面重置为初始状态。 这不是我想要的!

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

然后我完成了。