UIDeviceOrientation與UIinterfaceOrientation以及屏幕旋轉(zhuǎn)的方式

UIDeviceOrientation與UIinterfaceOrientation以及屏幕旋轉(zhuǎn)的方式

在日常開發(fā)過程中,經(jīng)常會遇到轉(zhuǎn)屏的需求,最近遇到一個轉(zhuǎn)屏相關(guān)的bug,順帶著總結(jié)下iOS端實現(xiàn)轉(zhuǎn)屏需要做的事情。

什么是設(shè)備方向,什么是視圖方向

首先需要明確兩個概念,設(shè)備方向(UIDeviceOrientation)和視圖方向(UIInterfaceOrientation)

UIDeviceOrientation:

不受鎖定屏幕方向的影響,通過

[UIDevice currentDevice].orientation

客觀反映出當(dāng)前設(shè)備所處的方向,與視野中正在展示視圖的方向無關(guān),該屬性只讀,無法修改

該屬性的變化可以通過監(jiān)聽UIDeviceOrientationDidChangeNotification來實時獲得設(shè)備方向的變化

UIInterfaceOrientation:

多數(shù)的旋轉(zhuǎn)都需要通過旋轉(zhuǎn)controller來實現(xiàn)。controller的方向也就是我上面提到的視圖方向,使用該枚舉UIInterfaceOrientation來表達。

如果想獲得當(dāng)前的視圖方向,可以通過以下代碼獲得

[UIApplication sharedApplication].statusBarOrientation

視圖方向的改變一定是由于設(shè)備方向發(fā)生了變化,設(shè)備方向的改變也只能是由于物理改變造成的。但是有一個例外,會在后面強制轉(zhuǎn)屏部分詳細說明。

如何讓Controller隨設(shè)備方向旋轉(zhuǎn)

1. 配置App支持的視圖方向

首先需要配置下當(dāng)前App能支持的視圖方向,所有使用的controller所能支持的視圖方向是該配置的子集;

可以通過以下兩種方法進行配置:

方法1,在Xcode選項中配置:

在Xcode->工程->General->Deployment Info中對Device Orientation進行配置,注意這里的Device Orientation不是上面所說的設(shè)備方向

方法2,在AppDelegate中通過代碼配置:

在AppDelegate中實現(xiàn)如下方法:

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {

return UIInterfaceOrientationMaskAll;

}

如果同時使用了兩種方式,那第二種使用代碼的方式會覆蓋第一種在Xcode中配置的方式

2. 配置Controller支持的方向

代碼很簡單,表示當(dāng)前Controller是否支持旋轉(zhuǎn),支持的方向都有什么,如下:

//是否支持轉(zhuǎn)屏

- (BOOL)shouldAutorotate

{

return YES;

}

//在支持轉(zhuǎn)屏的前提下,返回具體支持的方向

- (UIInterfaceOrientationMask)supportedInterfaceOrientations

{

return UIInterfaceOrientationMaskAll;

}

但是這段代碼具體要寫在哪個viewController中才有效果呢?

一個viewController是否可以旋轉(zhuǎn)并不是由他自己決定的,而是由rootViewController或者最上層被present上來的viewController來決定的。

每個App都有一個rootViewController,如果沒有通過present的方式推入controller,那么rootViewController支持的方向就決定了視圖方向;

如果有通過present的方式推入controller,那么最近的一次present操作對應(yīng)的controller就決定了視圖方向;

以上的代碼需要放在上面說到的決定了視圖方向的controller中

還有一個回調(diào)方法,決定了viewController出現(xiàn)時的視圖方向,該回調(diào)方法只對present方式進入界面的viewController有效果

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation

{

return UIInterfaceOrientationPortrait;

}

當(dāng)然還有一點最重要的,記得要在下拉框中打開設(shè)備的轉(zhuǎn)屏鎖,要不然怎么轉(zhuǎn)ViewController都不會跟著轉(zhuǎn)的

關(guān)于強制轉(zhuǎn)屏

在上文中提過,設(shè)備方向改變一定是由于物理改變造成的,其實這并不絕對

蘋果的API曾經(jīng)是允許修改[UIDevice currentDevice].orientation的,后來這個接口被干掉作為私有API了

但是我們還是可以通過一些其他方式繞過蘋果的限制來設(shè)置[UIDevice currentDevice].orientation,設(shè)備方向一旦改變,再符合上述視圖方向改變的條件,視圖方向就會被旋轉(zhuǎn),從而達到強制轉(zhuǎn)屏的效果

在實際開發(fā)過程中也會遇到類似的場景,比如播放器的全屏操作,就是一次強制的視圖方向改變

代碼如下:

NSNumber *orientationTarget = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];

[[UIDevice currentDevice] setValue:orientationTarget forKey:@"orientation"];

關(guān)于UINavigationController的旋轉(zhuǎn)

其實道理是一樣的,只不過如果present上來一個navigationController的時候,你需要想辦法讓這個navigationController去實現(xiàn)上述的shouldAutoRotate和supportedInterfaceOrientations方法,可以通過類別或繼承重寫的方式,這里也就不詳述了。




iOS的橫屏(Landscape)與豎屏(Portrait)InterfaceOrientation

0. 應(yīng)用級別的配置

大家(特指有iOS開發(fā)經(jīng)驗的人)應(yīng)該都知道Xcode Project的工程配置General頁簽中有那么四個圖(或者4個checkbox),標(biāo)識對四種interfaceOrientation的支持。分別為Portrait、PortraitUpsideDown、LandscapeLeft和LandscapeRight。

對應(yīng)的,在Xcode Project工程配置的Info頁,實際上就是Info.plist中,有對4種Orientation的記錄項。

這兩者是一樣的。

1. Window級別的控制

在iOS6.0之后,UIApplicationDelegate中多了一個方法聲明:

1- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window

就是對于特定的application和特定的window,我們需要支持哪些interfaceOrientation,這是可以通過實現(xiàn)這個方法定制的。

返回值是一個無符號整數(shù),實際上是可以使用定義好的枚舉值:

typedefNS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) {

UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),

UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),

UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),

UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),

UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),

UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),

UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),

};

對于UIApplicationDelegate的這個方法聲明,大多數(shù)情況下application就是當(dāng)前的application,而window通常也只有一個。所以基本上通過window對橫屏豎屏interfaceOrientation的控制相當(dāng)于全局的。

2. Controller層面的控制

老版本的iOS有這樣一個方法:

1- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientationNS_DEPRECATED_IOS(2_0, 6_0);

即定制是否可以旋轉(zhuǎn)到特定的interfaceOrientation。

而在iOS6之后,推出了2個新的方法來完成這個任務(wù):

1

2

- (BOOL)shouldAutorotateNS_AVAILABLE_IOS(6_0);

- (NSUInteger)supportedInterfaceOrientationsNS_AVAILABLE_IOS(6_0);

可以看得出來,兩個和在一起就是原來任務(wù)的完成過程。其中,大概的判斷方式是,先執(zhí)行前者,判斷是否可以旋轉(zhuǎn),如果為YES,則根據(jù)是否支持特定的interfaceOrientation再做決斷。

3. 使得特定ViewController堅持特定的interfaceOrientation

iOS6之后還提供了這樣一個方法,可以讓你的Controller倔強第堅持某個特定的interfaceOrientation:

1- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentationNS_AVAILABLE_IOS(6_0);

這就叫堅持,呵呵!

當(dāng)然,使用這個方法是有前提的,就是當(dāng)前ViewController是通過全屏的Presentation方式展現(xiàn)出來的。

這里使用的是另外一套枚舉量,可以去UIApplication.h中查看定義。

4. 當(dāng)前屏幕方向interfaceOrientation的獲取

有3種方式可以獲取到“當(dāng)前interfaceOrientation”:

controller.interfaceOrientation,獲取特定controller的方向

[[UIApplication sharedApplication] statusBarOrientation] 獲取狀態(tài)條相關(guān)的方向

[[UIDevice currentDevice] orientation] 獲取當(dāng)前設(shè)備的方向

具體區(qū)別,可參見StackOverflow的問答:

http://stackoverflow.com/questions/7968451/different-ways-of-getting-current-interface-orientation

5. 容器Controller的支持

上面把interfaceOrientation方向的獲取和支持配置都說了,看起來沒什么問題了。有沒有什么特殊情況?

當(dāng)你使用TabbarController和NavigationController按照如上做法使用的時候就會有些頭疼。

辦法不是沒有,比較通俗的一種就是——繼承實現(xiàn)。

6. UIView的transform屬性強制旋轉(zhuǎn).

最后一個方法是設(shè)置UIView的transform屬性來強制旋轉(zhuǎn).

見下代碼:

//設(shè)置statusBar[[UIApplication sharedApplication] setStatusBarOrientation:orientation];//計算旋轉(zhuǎn)角度float arch;if (orientation == UIInterfaceOrientationLandscapeLeft)? ? arch = -M_PI_2;else if (orientation == UIInterfaceOrientationLandscapeRight)? ? arch = M_PI_2;else? ? arch = 0;//對navigationController.view 進行強制旋轉(zhuǎn)self.navigationController.view.transform = CGAffineTransformMakeRotation(arch);self.navigationController.view.bounds = UIInterfaceOrientationIsLandscape(orientation) ? CGRectMake(0, 0, SCREEN_HEIGHT, SCREEN_WIDTH) : initialBounds;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • /* UIViewController is a generic controller base class th...
    DanDanC閱讀 2,030評論 0 2
  • [這是第11篇] 導(dǎo)語: iOS App中大多數(shù)頁面是只展示豎屏下的效果,但是少部分頁面需要支持橫豎屏。本文分別介...
    南華coder閱讀 14,613評論 18 93
  • iOS屏幕旋轉(zhuǎn)學(xué)習(xí)筆記iOS開發(fā)中使用屏幕旋轉(zhuǎn)功能的相關(guān)方法 1、基本知識點解讀 了解屏幕旋轉(zhuǎn)首先需要區(qū)分兩種 o...
    Laughingg閱讀 13,760評論 13 39
  • 由于講師訓(xùn)的第一次機會在我坐月子的時間,那時候由于剛生完孩子不到一星期的我,并不敢任性的看手機,然而也沒少操心。由...
    cindyzhao閱讀 264評論 0 0
  • 小時候, 門前長著一株不起眼的植物。 總是在夏末初秋之季, 靜靜地開著星星點點的小花兒。 因為它總是在傍晚時分開放...
    曉夢蝴蝶_331閱讀 574評論 6 10

友情鏈接更多精彩內(nèi)容