加速計是整個IOS屏幕旋轉的基礎,依賴加速計,設備才可以判斷出當前的設備方向,IOS系統共定義了以下七種設備方向:
typedef NS_ENUM(NSInteger, UIDeviceOrientation) { UIDeviceOrientationUnknown, UIDeviceOrientationPortrait, // Device oriented vertically, home button on the bottom UIDeviceOrientationPortraitUpsideDown, // Device oriented vertically, home button on the top UIDeviceOrientationLandscapeLeft, // Device oriented horizontally, home button on the right UIDeviceOrientationLandscapeRight, // Device oriented horizontally, home button on the left UIDeviceOrientationFaceUp, // Device oriented flat, face up UIDeviceOrientationFaceDown // Device oriented flat, face down };以及如下四種界面方向:
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) { UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown, UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight, UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft };一、UIKit處理屏幕旋轉的流程
當加速計檢測到方向變化的時候,會發出 UIDeviceOrientationDidChangeNotification 通知,這樣任何關心方向變化的view都可以通過注冊該通知,在設備方向變化的時候做出相應的響應。上一篇博客中,我們已經提到了在屏幕旋轉的時候,UIKit幫助我們做了很多事情,方便我們完成屏幕旋轉。
UIKit的相應屏幕旋轉的流程如下:
1、設備旋轉的時候,UIKit接收到旋轉事件。
2、UIKit通過AppDelegate通知當前程序的window。
3、Window會知會它的rootViewController,判斷該view controller所支持的旋轉方向,完成旋轉。
4、如果存在彈出的view controller的話,系統則會根據彈出的view controller,來判斷是否要進行旋轉。
二、UIViewController實現屏幕旋轉
在響應設備旋轉時,我們可以通過UIViewController的方法實現更細粒度的控制,當view controller接收到window傳來的方向變化的時候,流程如下:
1、首先判斷當前viewController是否支持旋轉到目標方向,如果支持的話進入流程2,否則此次旋轉流程直接結束。
2、調用 willRotateToInterfaceOrientation:duration:
方法,通知view controller將要旋轉到目標方向。如果該viewController是一個container view controller的話,它會繼續調用其content view controller的該方法。這個時候我們也可以暫時將一些view隱藏掉,等旋轉結束以后在現實出來。
3、window調整顯示的view controller的bounds,由於view controller的bounds發生變化,將會觸發 viewWillLayoutSubviews 方法。這個時候
self.interfaceOrientation和statusBarOrientation方向還是原來的方向。
4、接着當前view controller的 willAnimateRotationToInterfaceOrientation:duration:
方法將會被調用。系統將會把該方法中執行的所有屬性變化放到動animation block中。
5、執行方向旋轉的動畫。
6、最后調用 didRotateFromInterfaceOrientation:
方法,通知view controller旋轉動畫執行完畢。這個時候我們可以將第二部隱藏的view再顯示出來。
整個響應過程如下圖所示:
以上就是UIKit下一個完整的屏幕旋轉流程,我們只需要按照提示做出相應的處理就可以完美的支持屏幕旋轉。
三、注意事項和建議
1)注意事項
當我們的view controller隱藏的時候,設備方向也可能發生變化。例如view Controller A彈出一個全屏的view controller B的時候,由於A完全不可見,所以就接收不到屏幕旋轉消息。這個時候如果屏幕方向發生變化,再dismiss B的時候,A的方向就會不正確。我們可以通過在view controller A的viewWillAppear中更新方向來修正這個問題。
2)屏幕旋轉時的一些建議
- 在旋轉過程中,暫時界面操作的響應。
- 旋轉前后,盡量當前顯示的位置不變。
- 對於view層級比較復雜的時候,為了提高效率在旋轉開始前使用截圖替換當前的view層級,旋轉結束后再將原view層級替換回來。
- 在旋轉后最好強制reload tableview,保證在方向變化以后,新的row能夠充滿全屏。例如對於有些照片展示界面,豎屏只顯示一列,但是橫屏的時候顯示列表界面,這個時候一個界面就會顯示更多的元素,此時reload內容就是很有必要的。
注:以上內容和插圖全部來自蘋果官方文檔:View Controller Programming Guide for iOS