最近项目中要实现横竖屏的切换控制,研究了很多种不同的实现方法,总结了一种适配所有版本的横竖屏切换的通用方法。可以统一管理项目中的各个视图的横竖屏切换,,由各个视图控制器来控制各自支持的屏幕方向。目前完美适配IOS5、IOS6、IOS7、IOS8。
项目中如果通过 push方式切换视图,IOS的各个视图控制器的横竖屏控制权限是由根控制器控制的。即为与window第一个接触的视图控制器(self.window.rootViewController)。如果我们的项目通过 UINavigationController 来实现的,那么根控制器就是如下代码里的 RotateNavigationController。
注:使用这种方法的前提是 1)我们的项目通过 UINavigationController 来实现的,即根控制器是UINavigationController或者其子类。2)项目的 Device Orientation 设置为支持多方向的旋转。3)我们的视图切换是通过 pushViewController 来实现的。4)当我们从视图A(竖屏) push 切换到视图B(横屏) 的时候,视图不会自动发生横竖屏切换,而是只有当设备改变方向的时候才会根据代码中对应的方法设置去改变当前视图的横竖屏方向。即支持横竖屏切换操作。
1、在AppDelegate 方法中设置好扩展后的根视图控制器 RotateNavigationController
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
ONEViewController * one = [[ONEViewController alloc]init];
RotateNavigationController *nav = [[RotateNavigationController alloc]initWithRootViewController:one];
[self.window setRootViewController:nav];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
2、首先要子类化
UINavigationController,增加下面三个方法
//返回最上层的子Controller的shouldAutorotate
- (BOOL)shouldAutorotate{
return self.topViewController.shouldAutorotate;
}
//返回最上层的子Controller的supportedInterfaceOrientations
- (NSUInteger)supportedInterfaceOrientations{
return self.topViewController.supportedInterfaceOrientations;
}
//视图默认显示的方向
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return self.topViewController.preferredInterfaceOrientationForPresentation;
}
子类 RotateNavigationController 代码如下:
//
// RotateNavigationController.h
// AiCai
//
// Created by Jiabin He on 14-12-16.
// Copyright (c) 2014年 www.AiCai.com. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface RotateNavigationController : UINavigationController
@end
//
//
// RotateNavigationController.m
// AiCai
//
// Created by Jiabin He on 14-12-16.
// Copyright (c) 2014年 www.AiCai.com. All rights reserved.
//
#import "RotateNavigationController.h"
@implementation RotateNavigationController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//返回最上层的子Controller的shouldAutorotate
- (BOOL)shouldAutorotate{
return self.topViewController.shouldAutorotate;
}
//返回最上层的子Controller的supportedInterfaceOrientations
- (NSUInteger)supportedInterfaceOrientations{
return self.topViewController.supportedInterfaceOrientations;
}
//视图默认显示的方向
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return self.topViewController.preferredInterfaceOrientationForPresentation;
}
@end
这三个方法就是用来控制项目中所有的视图页面的横竖屏切换的。这三个方法是系统级的。不需要自己主动去调用,也会运行。
app启动首先走 main函数,然后main函数调用AppDelegate ,AppDelegate再调用UINavigationController,UINavigationController再调才是你的界面。UINavigationController 继承的也是UIViewController 。但他比UIViewController更进一步。所以我们各个视图的横竖屏控制是由各个控制器来独立控制的,而不再是根控制器。
往后,我们只要在对应的控制器上重写上面的这三个方法即可控制视图的横竖屏。
3、在这里必须注意的是,要使整个项目的视图都支持横竖屏幕切换,首先要设置 Device Orientation,上下左右四个方向就不能只勾选一个方向了,当然你要看你的项目所需要支持的方向,来判定,用哪几个点选哪几个。
、右旋横向模式。
4、横竖屏模式的切换(从视图A竖屏的切换到视图B横屏的)
假设视图A(ONEViewController)是竖屏的。根据AppDelegate方法中的设置,它是我的第一个页⾯。在视图A中重写扩展类RotateNavigationController中的三个方法。这里锁定纵向方向。
//支持纵向
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
//不支持自动旋转,不会因为设备方向改变而改变视图方向
- (BOOL)shouldAutorotate
{
return NO;
}
//当视图是通过 presentViewController 出来的时候,设定视图默认显示的方向为纵向
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
//IOS6以前的旋转控制方法,这里加上适配IOS5
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return toInterfaceOrientation == UIInterfaceOrientationPortrait;
}
即可实现视图A的纵向显示(方向是锁定的,不会因为设备方向改变而改变)。
然后在视图A中添加切换的按钮和动作,从竖屏视图A切换到横屏视图B(TWOViewController)
视图A中的部分代码
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(0, 0, 100, 200);
btn.center = self.view.center;
[btn addTarget:self action:@selector(clickBtn) forControlEvents:UIControlEventTouchUpInside];
btn.backgroundColor = [UIColor grayColor];
[self.view addSubview:btn];
}
-(void)clickBtn{
TWOViewController *viewC = [[TWOViewController alloc]init];
//这里使用push切换视图
[self.navigationController performSelector:@selector(pushViewController:animated:) withObject:viewC afterDelay:0.0];
//[self presentViewController:viewC animated:YES completion:Nil];
}
横屏视图B(TWOViewController)也要重写扩展类RotateNavigationController中的三个方法
//支持自动旋转,根据设备方向的改变而切换当前视图所支持的方向
- (BOOL)shouldAutorotate
{
return YES;
}
//支持横向
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
//当视图是通过 presentViewController 出来的时候,设定视图默认显示的方向为横向
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
<pre name="code" class="objc">//IOS6以前的旋转控制方法,这里加上适配IOS5
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return toInterfaceOrientation == UIInterfaceOrientationLandscapeRight;
}
到这里我们就可以统一管理项目中的各个视图的横竖屏切换,由各个视图控制器来控制各自支持的屏幕方向。
需要注意的是当视图A(纵向)切换到视图B(横向)的时候,视图A push 到视图B 后。视图B刚开始还是纵向的,因为扩展类 RotateNavigationController中的两个方法- shouldAutorotate 和 - supportedInterfaceOrientations 只有设备改变方向的时候才会被调用,光在视图控制器中覆写着两个方法是不行的。所以,当设备向逆时针方向横屏的时候,视图B马上调整为横屏布局模式。且调整为横屏之后锁定不变。如果想让视图B 支持多个方向的旋转可以改变supportedInterfaceOrientations 方法的返回参数实现。这里只做切换锁定横屏。
5、不过,很多种情况下实际的情况是我们需要从视图A(纵向)切换到视图B(横向)的时候是在切换的时候就转换好视图方向的,并且锁定横屏或竖屏。即视图A切换到视图B立马就变成横屏而不需要用户去改变设备的方向。那么我们这里要做的就是将上面切换视图的 push 方式改成 presentViewController 方式即可实现。(如果通过presentViewController方式切换视图那我们就不需要扩展UINavigationController类来重写UINavigationController那三个方法了,因为视图的选择方向控制由各个视图控制器决定,只需要在相应的控制器里重写即可)。我们可以在视图控制器B 中设置方法 preferredInterfaceOrientationForPresentation 。即当我们通过presentViewController方式切换视图的时候,我们可以设定视图默认显示的方向,这里为横向,并且触发。即可将视图B立马切换成横屏模式。 且锁定横屏方向。
视图A通过 presentViewController 方式切换到视图B,在视图B中重写方法切换到横屏后锁定横屏
//不支持自动旋转,不会因为设备方向改变而改变视图方向
- (BOOL)shouldAutorotate
{
return NO;
}
//支持横向
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
//当视图是通过 presentViewController 出来的时候,设定视图默认显示的方向为横向
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
//IOS6以前的旋转控制方法,这里加上适配IOS5
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return toInterfaceOrientation == UIInterfaceOrientationLandscapeRight;
}
我们还可以看到网上一些介绍强制横屏的方法,通过改变状态栏、使用私有API、将视图旋转90度等等的方法。不过由于系统版本的在横竖屏切换控制上差异比较大,有时候即使视图横屏显示了,但是我们的window还是纵向模式的,从而导致横屏视图上键盘弹窗的方向是从纵向弹出的。为了处理这一系列的问题,我觉得还是通过上面介绍的方法来控制整个项目视图控制器的横竖屏方向是最简单便捷的。