使用一个.xib文件替代纵向和横向的iOS布局

使用xcode中的界面生成器和一个.xib文件,如何在横向和纵向之间旋转时创build替代布局?

请参阅不同布局的图表 在这里输入图像说明

Nb 。 绿色视图/区域将包含横向stream动的3个项目和纵向的3个项目将在绿色视图/区域内垂直stream动。

一个办法是在你的.xib文件中有三个视图。 第一个是ViewController的普通视图,没有子视图。

然后,根据需要为纵向和横向创build视图。 所有这三个都必须是根级别的视图(看看截图)

在这里输入图像说明

在您的Viewcontroller中,创build2个IBOutlets,一个用于肖像,另一个用于横向视图,并将它们与界面构build器中的相应视图连接起来:

IBOutlet UIView *_portraitView; IBOutlet UIView *_landscapeView; UIView *_currentView; 

第三个视图_currentView需要跟踪当前显示哪个视图。 然后创build一个像这样的新function:

 -(void)setUpViewForOrientation:(UIInterfaceOrientation)orientation { [_currentView removeFromSuperview]; if(UIInterfaceOrientationIsLandscape(orientation)) { [self.view addSubview:_landscapeView]; _currentView = _landscapeView; } else { [self.view addSubview:_portraitView]; _currentView = _portraitView; } } 

您将需要从两个不同的地方调用此函数,首先进行初始化:

 -(void)viewDidLoad { [super viewDidLoad]; UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation]; [self setUpViewForOrientation:interfaceOrientation]; } 

第二个方向改变:

 -(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [self setUpViewForOrientation:toInterfaceOrientation]; } 

希望能帮到你!

没有自动的方式来支持,因为它是反对苹果devise。 你应该有一个ViewController支持两个方向。

但是如果你真的想这样做,你需要重新加载循环事件的xib,并加载不同的nib文件。

 -(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [[NSBundle mainBundle] loadNibNamed:[self nibNameForInterfaceOrientation:toInterfaceOrientation] owner:self options:nil]; [self viewDidLoad]; } - (NSString*) nibNameForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { NSString *postfix = (UIInterfaceOrientationIsLandscape(interfaceOrientation)) ? @"portrait" : @"landscape"; return [NSString stringWithFormat:@"%@-%@", NSStringFromClass([self class]), postfix]; } 

然后创build两个用“横向”和“纵向”固定的笔尖文件。

我喜欢@MeXx的解决scheme,但它具有在内存中保留两个不同视图层次结构的开销。 此外,如果任何子视图的状态(例如颜色)发生了变化,则在切换层次结构时,需要将其映射到整个视图。

另一种解决scheme可能是使用自动布局,并为每个方向交换每个子视图的约束。 如果两个方向上的子视图之间有1:1的映射关系,效果最好。

可以理解的是,您要使用IB来为每个方向直观地定义布局。 根据我的计划,您必须执行@MeXx所规定的操作,但是一旦加载了nib( awakeFromNib ),然后创build一个机制来存储两组约束,并在布局( viewWillLayoutSubviews )上重新应用正确的集合。 一旦你抓取并存储了它的约束条件,你可以扔掉二级视图层次结构。 (由于约束是特定于视图的,因此您可能会创build新的约束条件以应用于实际的子视图)。

对不起,我没有任何代码。 这只是在这个阶段的计划。

最后一点 – 用xib比故事板更容易一些,因为在故事板中,描述视图控制器主视图之外的视图是痛苦的(这是理想的,否则它是一个PITA编辑)。 Blach!

你可以肯定地先生

我以前做的是在Device旋转的时候手动给帧

每当设备旋转时, - (void)viewWillLayoutSubviews被调用

例如 – 在你的UIView取一个UIButton *button

 - (void)viewWillLayoutSubviews { if (UIDeviceOrientationIsLandscape([self.view interfaceOrientation])) { //x,y as you want [ button setFrame:CGRectMake:(x,y,button.width,button.height)]; } else { //In potrait //x,y as you want [ button setFrame:CGRectMake:(x,y,button.width,button.height)]; } } 

这样你就可以把它放在你喜欢的地方。 谢谢

请看看这些图片

我的xCode XIB UIView,我想在两个屏幕的第一个图像

在这里输入图像说明

现在,因为我想在风景-(void)viewWillLayoutSubviews这个视图,所以我去编辑我的-(void)viewWillLayoutSubviews

在这里输入图像说明

现在结果就是这样模拟器中的第一个图像

在这里输入图像说明

这是在景观

在这里输入图像说明

解决scheme与故事板[ios7]。 在主视图控制器里面,可以包含标签栏控制器的容器视图。 在标签栏控制器中,有2个选项卡。 一个选项卡用于纵向控制器,另一个选项用于横向模式控制器。

主视图控制器实现这些function:

 #define INTERFACE_ORIENTATION() ([[UIApplication sharedApplication]statusBarOrientation]) @interface MainViewController () @property(nonatomic,weak) UITabBarController *embeddedTabBarController; @end @implementation MainViewController - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"embedContainer"]) { self.embeddedTabBarController = segue.destinationViewController; [self.embeddedTabBarController.tabBar setHidden:YES]; } } - (void) adaptToOrientation:(UIInterfaceOrientation)interfaceOrientation { if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) { [self.embeddedTabBarController setSelectedIndex:1]; } else { [self.embeddedTabBarController setSelectedIndex:0]; } } - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { [self adaptToOrientation:interfaceOrientation]; } - (void) viewWillAppear:(BOOL)animated { [self adaptToOrientation:INTERFACE_ORIENTATION()]; } 

故事板中的segue链接应该被命名为“embedContainer”。

确保容器视图可以resize以满足父视图,在这两种情况下,横向和纵向。

注意一个事实,即在运行时,同一个控制器的两个实例同时存在。

故事板


更新: 替代横向视图控制器的Apple文档

我只想添加一个新的答案,以反映即将在ios8和XCode 6中的新function。

在最新的新软件中,苹果公司推出了尺寸类别 ,使故事板能够根据您使用的屏幕尺寸和方向进行智能调整。 虽然我build议你看一下上面的文档或者WWDC 2014会话, 用UIKit构build自适应应用程序 ,但我会试着去解释一下。

确保大小类别已启用 。

你会发现你的故事板文件现在是方形的。 你可以在这里设置基本的界面。 界面将被智能调整为所有启用的设备和方向。

在屏幕的底部,你会看到一个button说yAny xAny。 通过点击这个,你可以只修改一个尺寸类,例如风景和肖像。

我build议你阅读上面的文档,但我希望这可以帮助你,因为它只使用一个故事板。

您可以使用库GPOrientation。 这里是链接

以编程方式resize

我有一个应用程序,我有完全相同的情况。 在我的NIB,我只是没有肖像布局。 其他布局以编程方式执行。 以编程方式指定几个尺寸并不难,所以不需要维护两个NIB。

请注意,通过设置框架以编程方式执行视图更改将导致animation(或可以使用animation轻松制作)。 这将给用户一个有价值的反馈,即有关哪个组件移动到哪个位置。 如果你只是加载第二个视图,你将失去这种优势,从用户界面的angular度来看,我认为加载替代视图不是一个好的解决scheme。

使用两个ViewController

如果您喜欢使用两个ViewController,那么Apple会在开发人员文档中介绍如何执行此操作,例如,您可以在这里find答案: RespondingtoDeviceOrientationChanges 。

如果您想以编程方式执行此操作,则可以在方法didRotateFromInterfaceOrientation添加重定位代码。

我将该方法添加到我的ViewController中:

 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [self adjustLayoutToOrientation]; } 

然后执行布局的调整。 这是一个例子(代码是特定于我的应用程序,但你可以读取超级视图的大小,并从中计算子视图的框架。

 - (void)adjustLayoutToOrientation { UIInterfaceOrientation toInterfaceOrientation = self.interfaceOrientation; bool isIPhone = !([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad); [self adjustViewHeight]; [self adjustSubviewsToFrame: [mailTemplateBody.superview.superview frame]]; CGRect pickerViewWrapperFrame = pickerViewWrapper.frame; if(isIPhone) { pickerViewWrapperFrame.origin.x = 0; pickerViewWrapperFrame.size.height = keyboardHeight; pickerViewWrapperFrame.origin.y = [self view].frame.size.height-pickerViewWrapperFrame.size.height; pickerViewWrapperFrame.size.width = [self view].frame.size.width; } else { pickerViewWrapperFrame = pickerView.frame; } // MORE ADJUSTMENTS HERE }