我需要为肖像和风景使用不同的xib文件。我没有使用自动布局,但我使用的是iOS6。 (如果您关心原因,请参阅my previous question。)
我正在关注Adam对使用amergin的initWithNib名称技巧修改的this question的回答,并根据我自己的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);
}
在我的代表中。
我有两个可能相关的问题。首先,简单的一个。我不颠倒旋转。我已经在iPad和iPhone的xcode中打开了所有正确的位。这可能是一个单独的问题,也可能是我问题的核心。
真正的问题是,当我旋转到横向模式时,我的xib会被替换,但视图会偏离90度。
这是我的2 xib的样子。 (我把它们弄得很漂亮,所以你可以看出它们是不同的。)
和
你可以看到我运行它(最初是在横向模式下)时横向xib是否正确。
当我旋转到肖像时它也是正确的
但是当我旋转回横向时,xib会被替换,但视图会偏离90度。
这里有什么问题?
答案 0 :(得分: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类型的调用一样简单。如果我弄清楚,我会为未来的读者编辑这个答案。
归功于Sakti对Easiest way to support multiple orientations? How do I load a custom NIB when the application is in Landscape?的评论,我第一次阅读时不应忽略这些评论:
我将视图控制器添加到导航控制器并显示它 这使它按预期工作
编辑:为示例代码添加了额外的行来隐藏导航栏,因为大多数人都不希望这样做。
答案 1 :(得分: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];
}
答案 2 :(得分:0)
我在这里回答了我自己的问题,在我的iOS博客http://www.notthepainter.com/topologically-challenged-ui/
上写完整篇文章。我有一个朋友帮助我,他在一个xib文件中使用了2个视图,其中IBOutlets用于纵向和横向视图,他在它们之间切换设备旋转。完美,对吗?好吧,不,当你在XIB中有2个视图时,你无法将你的IBOutlets连接到这两个地方。我让它在视觉上有效,但我的控件只能在一个方向上工作。
我最终提出了使用定向主视图控制器的想法,该控制器在设备旋转时加载容器视图控制器。这工作得很好。让我们看看代码:
-(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 Controllers的博客条目,那么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来检查我们的bundle中是否存在xib。如果是,我们返回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类时,我打破了模型 - 视图 - 控制器设计模式!这很容易做到,Apple已经通过将View和Controller放在同一个类中来帮助我们。并且很容易在VC的.h文件中不小心混合模型数据。我完成了那个。当我运行上面的代码时,它工作得很好,我可以整天旋转它,两个方向的UI都是正确的。但是当我在运动计时器运行时旋转设备时,您认为发生了什么?是的,他们都被删除了,UI重置为初始状态。这根本不是我想要的!
我创建了一个XTMUser类来保存所有的计时数据,我将所有NSTimers放入XTMOrientationMasterViewController类,然后我制作了一个协议,以便XTMOrientationMasterViewController可以响应XTMViewController类中的UI点击。
然后我就完成了。