前提:
你需要把controller.view作為window的subview,也即是需要設(shè)置window的rootViewController,直接把controller的view添加到window上是不行的,如果我們不設(shè)置window的rootViewController,那么屏幕局的旋轉(zhuǎn)只能有UIApplication對(duì)象來(lái)控制,而且屏幕旋轉(zhuǎn)時(shí)controllers也將拿不到通知,導(dǎo)致轉(zhuǎn)屏失效。
- 1
從iOS6開(kāi)始,在controller中我們可以通過(guò)覆蓋
-(UIInterfaceOrientationMask)supportedInterfaceOrientations;
這個(gè)方法來(lái)限制屏幕旋轉(zhuǎn)的方向,如果不重寫,那么在iPad上返回UIInterfaceOrientationMaskAll(所有方向),iphone則返回UIInterfaceOrientationMaskAllButUpsideDown(除了上下顛倒外的方向),如果某個(gè)controller不需要在多個(gè)方向展示其內(nèi)容,那么就不需要重寫此方法。官方解釋為:
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開(kāi)始,UIKit開(kāi)始使用UIApplication和最頂層的controller(topmost controller)來(lái)決定支持的方向,在Info.plist中有一個(gè)字段UISupportedInterfaceOrientations,它包含了你的應(yīng)用所支持的屏幕方向,它和你在target的general中的設(shè)置是一一對(duì)應(yīng)的,通常我們修改其中的一個(gè)地方,另外一個(gè)地方就會(huì)跟著發(fā)生變化:


對(duì)于UIApplication,可以在APPDelegate中通過(guò)以下方法來(lái)設(shè)置應(yīng)用所支持的方向:
//此方法替換了之前在plist和target中設(shè)置的屏幕方向,例如:如果之前設(shè)置的是只支持豎屏,在這可以修改為只支持橫屏或其他,那么修改完成后應(yīng)用就支持了現(xiàn)在所設(shè)置的方向,當(dāng)然我們?nèi)匀豢梢栽O(shè)置支持多方向,和在plist及target中設(shè)置的效果是等同的
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
return UIInterfaceOrientationMaskPortrait;
}
-
特別注意:
這里的最頂層的controller(topmost controller)定義一般情況是window的rootViewController,只有在present到另外一個(gè)controller后tiomost controller 才會(huì)變成被present的那個(gè)controller,也就是topmost controller只有兩種情況,要么是rootViewController,要么就是present的后的controller,特別要與navigation controller的topViewController和visibleController區(qū)分開(kāi),如果解釋的不是很明白,那么我們來(lái)看一下官方解釋:
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.
這也就是為什么當(dāng)我們?cè)O(shè)置NAVigationController為rootViewController,在push到的子頁(yè)面再去改變子controller的屏幕方向時(shí)沒(méi)有效果的原因,因?yàn)閜ush到的子controller不是topmost controller,自然也就無(wú)法直接去控制屏幕的旋轉(zhuǎn),網(wǎng)上的解決方法很多說(shuō)是在navigation controller中去調(diào)用它的topViewController里面的方法,我試了一下發(fā)現(xiàn)并沒(méi)有什么用,如下:
//在navigation controller中重寫
-(BOOL)shouldAutorotate{
return [self.topViewController shouldAutorotate];
}
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return [self.topViewController supportedInterfaceOrientations];
}
不知道是我哪個(gè)地方漏掉一部分東西還是其它什么原因,push過(guò)去后界面仍然是不會(huì)發(fā)生旋轉(zhuǎn)的。
- 3 iOS6+ 的強(qiáng)制橫屏
iOS5就不說(shuō)了,從iOS6及以后控制屏幕的方向的方法,分兩種情況:
(1) vc是present進(jìn)來(lái)的,可以直接重寫下面的方法:
//是否支持自動(dòng)旋轉(zhuǎn),如果要強(qiáng)制橫屏則需要設(shè)為NO(跳轉(zhuǎn)到此頁(yè)面需要用present的方式,否則強(qiáng)制橫屏沒(méi)有作用)
-(BOOL)shouldAutorotate{
return NO;
}
//首選方向(如果支持的方向比較多,可以設(shè)置此方向,那么剛進(jìn)入這個(gè)界面時(shí)顯示的就是此方向)
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationLandscapeRight;
}
//在某個(gè)controller中可以重寫此方法來(lái)達(dá)到設(shè)置支持的屏幕方向的目的,在iPad上默認(rèn)返回UIInterfaceOrientationMaskAll,而在iphone上默認(rèn)返回UIInterfaceOrientationMaskAllButUpsideDown,如果controller上的內(nèi)容僅僅需要在某個(gè)方向上去展示那么需要覆蓋此方法,否則不需要
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscapeRight;
}
(2) vc是push進(jìn)來(lái)的,上面的方法就不會(huì)起作用了,我現(xiàn)在所能想到的方法是旋轉(zhuǎn)view:
//進(jìn)入界面旋轉(zhuǎn)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);
}
//退出界面,恢復(fù)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);
}
當(dāng)屏幕旋轉(zhuǎn)時(shí)系統(tǒng)會(huì)為我們發(fā)出一個(gè)通知:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(screenChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
我們可以監(jiān)測(cè)此通知做一些事情,比如界面的重新布局等等,但是如果我們采用push進(jìn)來(lái)的方法而且是通過(guò)改變window來(lái)達(dá)到旋轉(zhuǎn)(實(shí)際上是假旋轉(zhuǎn))的話,那么系統(tǒng)不會(huì)發(fā)出通知,我們自然也就監(jiān)聽(tīng)不到。而在實(shí)際應(yīng)用中,如果想要某個(gè)界面強(qiáng)制橫屏,那么用present的方式就已經(jīng)完全可以滿足要求了,而且很多應(yīng)用采用的也是present的方式,當(dāng)然誰(shuí)如果有解決push更好的解決辦法,還請(qǐng)賜教,謝謝!
-
總結(jié)
1、全局控制app是否支持屏幕旋轉(zhuǎn)有三種方式可選:target、plist、和UIApplication
2、present進(jìn)來(lái)的vc可以直接重寫三方法來(lái)控制屏幕旋轉(zhuǎn)
3、push進(jìn)來(lái)的vc通過(guò)改變window的transform來(lái)實(shí)現(xiàn)偽旋轉(zhuǎn)
- End