iOS学习笔记03--屏幕旋转

前提:
你需要把controller.view作为window的subview,也即是需要设置window的rootViewController,直接把controller的view添加到window上是不行的,如果我们不设置window的rootViewController,那么屏幕局的旋转只能有UIApplication对象来控制,而且屏幕旋转时controllers也将拿不到通知,导致转屏失效。

  • 1
    从iOS6开始,在controller中我们可以通过覆盖
-(UIInterfaceOrientationMask)supportedInterfaceOrientations;

这个方法来限制屏幕旋转的方向,如果不重写,那么在iPad上返回UIInterfaceOrientationMaskAll(所有方向),iphone则返回UIInterfaceOrientationMaskAllButUpsideDown(除了上下颠倒外的方向),如果某个controller不需要在多个方向展示其内容,那么就不需要重写此方法。官方解释为:

There is little need to override this method unless the content managed by the view controller must only be displayed in a subset of these orientations. If you override this method, your implementation must return a bitwise combination of UIInterfaceOrientationMask values.

在iOS5及以下则采用:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation


  • 2
    从ios6开始,UIKit开始使用UIApplication和最顶层的controller(topmost controller)来决定支持的方向,在Info.plist中有一个字段UISupportedInterfaceOrientations,它包含了你的应用所支持的屏幕方向,它和你在target的general中的设置是一一对应的,通常我们修改其中的一个地方,另外一个地方就会跟着发生变化:
plist中的设置.png

target中的设置.png

对于UIApplication,可以在APPDelegate中通过以下方法来设置应用所支持的方向:

//此方法替换了之前在plist和target中设置的屏幕方向,例如:如果之前设置的是只支持竖屏,在这可以修改为只支持横屏或其他,那么修改完成后应用就支持了现在所设置的方向,当然我们仍然可以设置支持多方向,和在plist及target中设置的效果是等同的
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
    return UIInterfaceOrientationMaskPortrait;
}
  • 特别注意:
    这里的最顶层的controller(topmost controller)定义一般情况是window的rootViewController,只有在present到另外一个controller后tiomost controller 才会变成被present的那个controller,也就是topmost controller只有两种情况,要么是rootViewController,要么就是present的后的controller,特别要与navigation controller的topViewController和visibleController区分开,如果解释的不是很明白,那么我们来看一下官方解释:

Important: Here, the topmost view controller refers to the window's root view controller unless another view controller is currently presented, in which case, the presented view controller becomes the topmost view controller for the duration it is presented. This should not be confused with thetopViewController
of a navigation controller.

这也就是为什么当我们设置NAVigationControllerrootViewController,在push到的子页面再去改变子controller的屏幕方向时没有效果的原因,因为push到的子controller不是topmost controller,自然也就无法直接去控制屏幕的旋转,网上的解决方法很多说是在navigation controller中去调用它的topViewController里面的方法,我试了一下发现并没有什么用,如下:

//在navigation controller中重写
-(BOOL)shouldAutorotate{
    return [self.topViewController shouldAutorotate];
}
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
    return [self.topViewController supportedInterfaceOrientations];
}

不知道是我哪个地方漏掉一部分东西还是其它什么原因,push过去后界面仍然是不会发生旋转的。

  • 3 iOS6+ 的强制横屏
    iOS5就不说了,从iOS6及以后控制屏幕的方向的方法,分两种情况:
    (1) vc是present进来的,可以直接重写下面的方法:
//是否支持自动旋转,如果要强制横屏则需要设为NO(跳转到此页面需要用present的方式,否则强制横屏没有作用)
-(BOOL)shouldAutorotate{
    return NO;
}
//首选方向(如果支持的方向比较多,可以设置此方向,那么刚进入这个界面时显示的就是此方向)
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return UIInterfaceOrientationLandscapeRight;
}
//在某个controller中可以重写此方法来达到设置支持的屏幕方向的目的,在iPad上默认返回UIInterfaceOrientationMaskAll,而在iphone上默认返回UIInterfaceOrientationMaskAllButUpsideDown,如果controller上的内容仅仅需要在某个方向上去展示那么需要覆盖此方法,否则不需要
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

(2) vc是push进来的,上面的方法就不会起作用了,我现在所能想到的方法是旋转view:

//进入界面旋转window
-(void)viewWillAppear:(BOOL)animated{
    self.navigationController.view.window.transform = CGAffineTransformMakeRotation(M_PI_2);
    self.navigationController.view.window.bounds = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.height, [[UIScreen mainScreen] bounds].size.width);
}
//退出界面,恢复window
-(void)viewWillDisappear:(BOOL)animated{
    self.navigationController.view.window.transform = CGAffineTransformMakeRotation(0);
    self.navigationController.view.window.bounds = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height);
}

当屏幕旋转时系统会为我们发出一个通知:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(screenChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];

我们可以监测此通知做一些事情,比如界面的重新布局等等,但是如果我们采用push进来的方法而且是通过改变window来达到旋转(实际上是假旋转)的话,那么系统不会发出通知,我们自然也就监听不到。而在实际应用中,如果想要某个界面强制横屏,那么用present的方式就已经完全可以满足要求了,而且很多应用采用的也是present的方式,当然谁如果有解决push更好的解决办法,还请赐教,谢谢!


  • 总结
    1、全局控制app是否支持屏幕旋转有三种方式可选:target、plist、和UIApplication
    2、present进来的vc可以直接重写三方法来控制屏幕旋转
    3、push进来的vc通过改变window的transform来实现伪旋转

  • End
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容