UI -- IOS6屏幕旋转问题总结

第一篇详细介绍ios6下设备旋转设置问题

         IOS6屏幕旋转详解(自动旋转、手动旋转、兼容IOS6之前系统)

自:http://blog.csdn.net/cococoolwhj/article/details/8208991

概述:

在iOS6之前的版本中,通常使用 shouldAutorotateToInterfaceOrientation 来单独控制某个UIViewController的方向,需要哪个viewController支持旋转,只需要重写shouldAutorotateToInterfaceOrientation方法。

但是iOS 6里屏幕旋转改变了很多,之前的 shouldAutorotateToInterfaceOrientation 被列为 DEPRECATED 方法,查看UIViewController.h文件也可以看到:

[cpp]  view plain copy
  1. // Applications should use supportedInterfaceOrientations and/or shouldAutorotate..  
  2. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation NS_DEPRECATED_IOS(2_0, 6_0);  

程序将使用如下2个方法来代替:

[cpp]  view plain copy
  1. - (BOOL)shouldAutorotate;  
  2. - (NSUInteger)supportedInterfaceOrientations;  
除了重写这个2个方法,IOS6里面要旋转还有一些需要注意的地方,下面会细述。另外还有一个硬性条件,需要在Info.plist文件里面添加程序支持的所有方向,可以通过以下2种方式添加

1.



2.



另外要兼容IOS6之前的系统,要保留原来的 shouldAutorotateToInterfaceOrientation 方法,还有那些 willRotateToInterfaceOrientation 等方法。


IOS6自动旋转设置:

IOS6里面,控制某个viewController旋转并不是像IOS5或者IOS4一样在这个viewController里面重写上面那2个方法,而是需要在这个viewController的rootViewController(根视图控制器)里面重写,怎么解释呢?就是最前面的那个viewController,直接跟self.window接触的那个controller,比如以下代码:
[cpp]  view plain copy
  1. UIViewController *viewCtrl = [[UIViewController alloc] init];  
  2. UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:viewCtrl];  
  3. if ([window respondsToSelector:@selector(setRootViewController:)]) {  
  4.     self.window.rootViewController = navCtrl;  
  5. else {  
  6.     [self.window addSubview:navCtrl.view];  
  7. }  
如果需要设置viewCtrl的旋转,那么不能在UIViewController里面重写 shouldAutorotate和supportedInterfaceOrientations方法,而是需要在navCtrl里面设置,又因为UINavigationController是系统控件,所以这里需要新建一个UINavigationController的子navigationController的子类,然后在里面实现shouldAutorotate和supportedInterfaceOrientations方法,比如:
[cpp]  view plain copy
  1. -(NSUInteger)supportedInterfaceOrientations{  
  2.     return UIInterfaceOrientationMaskAllButUpsideDown;  
  3. }  
  4.   
  5. - (BOOL)shouldAutorotate{  
  6.     return YES;  
  7. }  
eg1:如果上面的例子是self.window.rootViewController = viewCtrl,而不是navCtrl,那么上面的那2个控制旋转的方法就应该写在UIViewController里面!

eg2:如果viewCtrl又 pushViewController到viewCtrl2,需要设置viewCtrl2的旋转,怎么办呢? 还是在navCtrl里面控制,因为viewCtrl和viewCtrl2的rootViewController都是navCtrl,一般的写法都是
[cpp]  view plain copy
  1. UIViewController *viewCtrl2 = [[UIVewController alloc] init];  
  2. [self.navigationController.navigationController pushViewController:viewCtrl2 animated:YES];  
所以要控制一个UINavigationController push到的所有viewController的旋转,那么就得在navCtrl里面区分是哪个viewController,以便对他们一一控制!同样如果rootViewController是UITabbarController,那么需要在子类化的 UITabbarController里面重写那2个方法,然后分别控制!

但是有时候我初始化UINavigationController的时候,并不知道所有我所有需要push到的viewController,那么这里有一个通用的方法,就是让viewController自己来控制自己,首先在navCtrl里面的实现方法改为以下方式:
[cpp]  view plain copy
  1. - (BOOL)shouldAutorotate    
  2. {    
  3.     return self.topViewController.shouldAutorotate;    
  4. }    
  5.     
  6. - (NSUInteger)supportedInterfaceOrientations    
  7. {    
  8.     return self.topViewController.supportedInterfaceOrientations;    
  9. }  
全部调用self.topViewController,就是返回当前呈现出来的viewController里面的设置,然后在viewCtrl、viewCtrl2等等这些viewController里面重写 shouldAutorotate和 supportedInterfaceOrientations,以方便设置每个viewController的旋转

eg3:如果viewCtrl 是 
presentModalViewController 到 viewCtrl3,那么viewCtrl3的旋转设置就不在navCtrl里面了!如果presentModalViewController的viewController是navController、tabbarController包装过的viewCtrl3,那么就应在新包装的navController、tabbarController里面设置,如果是直接presentModalViewController到viewCtrl3,那么就在viewCtrl3里面设置


IOS5、IOS4自动旋转设置

这个简单很多,没有上面的硬性条件,只需要在需要旋转的viewController里面重写 shouldAutorotateToInterfaceOrientation 方法就行

手动旋转

手动旋转也有2种方式,一种是直接设置 UIDevice 的 orientation,但是这种方式不推荐,上传appStore有被拒的风险:

[cpp]  view plain copy
  1. if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {  
  2.     [[UIDevice currentDevice] performSelector:@selector(setOrientation:) withObject:(id)UIInterfaceOrientationPortrait];  
  3. }  
第二种是假旋转,并没有改变   UIDevice 的 o rientation,而是 改变某个view的  transform,利用  CGAffineTransformMakeRotation  来达到目的,比如:
[cpp]  view plain copy
  1. self.view.transform = CGAffineTransformMakeRotation(M_PI/2)  

下面讲解采用第二种方式的各版本手动旋转:

思想是首先设置 statusBarOrientation,然后再改变某个view的方向跟 statusBarOrientation 一致!


IOS6手动旋转:

1. 那既然是旋转,最少也得有2个方向,那么还是少不了上面说的那个硬性条件,先在plist里面设置好所有可能需要旋转的方向。既然是手动旋转,那么就要关闭自动旋转:

[cpp]  view plain copy
  1. - (BOOL)shouldAutorotate{  
  2.         return NO;  
  3. }  
2.手动触发某个按钮,调用方法,这个方法的实现如下:
[cpp]  view plain copy
  1. [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];  
  2. self.view.transform = CGAffineTransformMakeRotation(M_PI/2);  
  3. self.view.bounds = CGRectMake(0, 0, kScreenHeight, 320);  
注意:
1. 只需要改变self.view.transform,那么self.view的所有subview都会跟着自动变;其次因为方向变了,所以self.view的大小需要重新设置,不要使用self.view.frame,而是用bounds。
2. 如果shouldAutorotate 返回YES的话,下面设置setStatusBarOrientation 是不管用的!setStatusBarOrientation只有在shouldAutorotate 返回NO的情况下才管用!

IOS5、IOS4手动旋转:

1.在需要手动旋转的viewController里的 shouldAutorotateToInterfaceOrientation 方法设置 interfaceOrientation == [UIApplicationsharedApplication].statusBarOrientation
[cpp]  view plain copy
  1. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{  
  2.     return (interfaceOrientation == [UIApplication sharedApplication].statusBarOrientation);  
  3. }  
2.手动触发某个按钮,调用方法,这个方法的实现如下:
[cpp]  view plain copy
  1. [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];  
  2. self.view.transform = CGAffineTransformMakeRotation(M_PI/2);  
  3. self.view.bounds = CGRectMake(0, 0, kScreenHeight, 320);  
注意:只需要改变self.view.transform,那么self.view的所有subview都会跟着自动变;其次因为方向变了,所以self.view的大小需要重新设置,不要使用self.view.frame,而是用bounds。


经验分享:

1.IOS6里面,如果一个项目里面需要各种旋转支持,有自动,有手动,那么我们可以新建2个navController或者tabbarController的子类,一个是不旋转,一个旋转,那么所有需要旋转的UINavigationController都可以用这个子类来代替!包括我们可以定制短信呀、邮件呀的旋转!
2.supportedInterfaceOrientations 方法一般是写UIInterfaceOrientationMask方向,但是如果程序要兼容4.3以下的SDK(4.3以下的SDK必须是4.5以下的Xcode,不支持IOS6),那么在用4.5以下的Xcode编译的时候通不过!所以可以用statusBarOrientation代替或者直接写死数字!
[cpp]  view plain copy
  1. -(NSUInteger)supportedInterfaceOrientations{  
  2.     return [UIApplication sharedApplication].statusBarOrientation;  
  3. }  
3.一般都不建议在程序里面直接调用 UIDeviceOrientation 的方向,而是用 UIInterfaceOrientation,他们之间是不同的!
[cpp]  view plain copy
  1. UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,  
  2. UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft  
看到吗,左右是反的!Xcode图形化设置方向也是以 UIInterfaceOrientation 为准,就是home按键所在的方向

参考:
http://blog.csdn.net/totogogo/article/details/8002173
http://stackoverflow.com/questions/13200220/how-to-change-keyboard-orientation-in-ios6
http://blog.csdn.net/yiyaaixuexi/article/details/8035014

第二篇文章:讲解旋转过程中的各个方法调用

         ios6 设备旋转以及获取设备方向

1.在APPDelegate里,将
[self.window addSubview:self.viewController.view];  

改为判断当前设备系统  
     if ([[[UIDevice currentDevice] systemVersion] floatValue]>=4.0) {  
         //4.0以后支持  
         self.window.rootViewController = self.viewController;  
       }  
     else  
         [self.window addSubview:self.viewController.view];  

2.在viewController.m中重写方法

//ios6以后设备旋转  
    - (BOOL)shouldAutorotate  
    {  
        return YES;  
    }  
    - (NSUInteger)supportedInterfaceOrientations  
    {  
        NSLog(@"ios6");  
        return UIInterfaceOrientationMaskAll;  
    //    self.interfaceOrientation  
          
    }  
    - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation  
    {  
        NSLog(@"设备旋转");  
    }  

要翻转的时候,首先响应的方法:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

return YES则支持翻转,NO则不支持。

紧接着

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

被调用。这个方法是发生在翻转开始之前。一般用来禁用某些控件或者停止某些正在进行的活动,比如停止视频播放。
再来是

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

这个方法发生在翻转的过程中,一般用来定制翻转后各个控件的位置、大小等。可以用另外两个方法来代替:willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:   和  willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:

最后调用的是

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation

这个方法发生在整个翻转完成之后。一般用来重新启用某些控件或者继续翻转之前被暂停的活动,比如继续视频播放


3,在info。plist中增加相对应的方向即可


4.获取自身屏幕方法,不要使用[[UIDevice currentDevice] orientation](第一次使用的时候,总是返回0)
而是要使用self.interfaceOrientation或[[UIApplication sharedApplication] statusBarOrientation]

第三篇讲收到设备旋转的通知后调用设置坐标方法

横竖屏切换,视图乱了怎么办?

首先,我们必须了解一下下列4种状态,它们被用来描述设备旋转方向:

UIInterfaceOrientationLandscapeLeft

向左,即HOME键在右

UIInterfaceOrientationLandscapeRight

向右,即HOME键在左

UIInterfaceOrientationPortrait

正立,即HOME键在下

UIInterfaceOrientationPortraitUpsideDown

倒立,即HOME键在上

 

对于旋屏的处理,大致分为如下几种情况和思路:

也许,你不需要旋屏支持,而希望锁定屏幕

1-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
2{
3    returnNO;
4}

 

也许,你需要支持旋屏,或者支持部分方向的旋屏

1-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
2       return(interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
3}


也许,你的view有张背景图,旋屏时系统帮助你拉伸了图片,但是却没有管你的其它部件,比如button,你希望直接改变button的大小和位置

01-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
02{
03    if(UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
04        NSLog(@"现在是竖屏");
05        [btn setFrame:CGRectMake(213, 442, 340, 46)];
06    }
07    if(UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
08        NSLog(@"现在是横屏");
09        [btn setFrame:CGRectMake(280, 322, 460, 35)];
10    }
11}

 

也许,你并不希望用绝对坐标去约束控件,而是希望让它通过旋转自己适应屏幕的旋转

01- (void)viewDidLoad
02{
03    [super viewDidLoad];
04    // Do any additional setup after loading the view, typically from a nib.
05    UIDevice *device = [UIDevice currentDevice];
06    [device beginGeneratingDeviceOrientationNotifications];
07    //利用 NSNotificationCenter 获得旋转信号 UIDeviceOrientationDidChangeNotification
08    NSNotificationCenter *ncenter = [NSNotificationCenter defaultCenter];
09    [ncenter addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:device];
10}
11 
12- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
13{
14    return(interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
15}
16 
17-(void)rotation_btn:(float)n
18{
19    UIButton *robtn = self.btn;
20    robtn.transform = CGAffineTransformMakeRotation(n*M_PI/180.0);
21}
22 
23-(void)orientationChanged
24{
25    UIDeviceOrientation orientaiton = [[UIDevice currentDevice] orientation];
26     
27    switch(orientaiton) {
28        caseUIDeviceOrientationPortrait:            
29            [self  rotation_btn:0.0];
30            break;
31        caseUIDeviceOrientationPortraitUpsideDown: 
32            [self  rotation_btn:90.0*2];
33            break;
34        caseUIDeviceOrientationLandscapeLeft:    
35            [self  rotation_btn:90.0*3];
36            break;
37        caseUIDeviceOrientationLandscapeRight: 
38            [self  rotation_btn:90.0];
39            break;
40        default:
41            break;
42    }
43}

也许,你需要autoresizesSubviews = YES

也许,你希望横竖屏有不同的布局效果,需要准备2份Subview,在不同状态去替换


 

当然不要忘记,需要调节设定图示中的1、2处
iOS开发 - 戏说旋屏


转自:http://blog.csdn.net/yiyaaixuexi/article/details/7670852 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值