這段時間做的一個app,需求是大部分界面豎屏,播放器頁面橫屏,網頁播放可橫屏可豎屏。查閱了一些資料,也踩了一些坑, 在這里做一個總結。
iOS如何支持旋屏
1. project->target->Deployment Info->Device Orientation

這里的Landscape Left是Device Orientation,是指內容的方向,即此時手機向右旋轉,home鍵在左邊;而Landscape Right表示手機向右左旋轉,home鍵在右邊
2. 代碼控制
在AppDelegate中添加方法
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskAll;
}
當使用代碼控制旋屏方向時,第一點的Device Orientation配置就失效了
關于旋屏之后狀態欄消失的問題,解決辦法是在需要旋屏的UIViewController中重寫3個方法
//設置樣式
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleDefault;
}
//設置是否隱藏
- (BOOL)prefersStatusBarHidden {
return NO;
}
//設置隱藏動畫
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
return UIStatusBarAnimationNone;
}
如果不想在ViewController中都去重寫,可以選擇
- 繼承一個基類ViewController,在基類中重寫上述3個方法
- 新建Category
@implementation UIViewController (StatusBarCategory)
//設置樣式
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleDefault;
}
//設置是否隱藏
- (BOOL)prefersStatusBarHidden {
return NO;
}
//設置隱藏動畫
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
return UIStatusBarAnimationNone;
}
@end
如果風格統一,推薦第二種寫法,盡量減少使用繼承;若需要定制狀態欄,可以使用第一種方案
那么現在來說說需要解決旋屏的需求
通常app大部分界面豎屏,有的界面強制橫屏,如播放器,而有的界面支持橫豎屏,如UIWebView
因為所有的旋屏都會走AppDelegate的方法
-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window;
所以在AppDelegate.h暴露2個參數
@property (nonatomic, assign) BOOL allowRotate;
@property (nonatomic, assign) UIInterfaceOrientationMask interfaceOrientation;
AppDelegate.m中
//初始化參數
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.allowRotate = NO;
self.interfaceOrientation = UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return self.allowRotate?self.interfaceOrientation:UIInterfaceOrientationMaskPortrait;
}
在需要旋屏的ViewController中
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
((AppDelegate *)[UIApplication sharedApplication].delegate).allowRotate = YES;
//需要旋屏支持的方向
((AppDelegate *)[UIApplication sharedApplication].delegate).interfaceOrientation = UIInterfaceOrientationMaskLandscapeRight;
//強制旋屏
[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeRight) forKey:@"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
((AppDelegate *)[UIApplication sharedApplication].delegate).allowRotate = NO;
//還原豎屏
((AppDelegate *)[UIApplication sharedApplication].delegate).interfaceOrientation = UIInterfaceOrientationMaskPortrait;
//強制旋屏,還原豎屏
[[UIDevice currentDevice] setValue:@(UIDeviceOrientationPortrait) forKey:@"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
}
其中比較重要的一行
[UIViewController attemptRotationToDeviceOrientation];
當你發生屏幕旋轉時調用這句代碼,可以解決一些奇怪的bug,比如橫屏返回后,本應豎屏的界面也是橫屏等。
結語
在測試當中,碰到一些問題:
- 旋屏后的手勢返回問題,這個問題可以通過禁用返回手勢解決
- 依然會有push后不橫屏的情況,但是概率不高,在能接受的范圍,具體原因不詳,若有解決方案的朋友歡迎來交流。