iOS屏幕旋轉一直是一個清晰又模糊的概念,看似簡單,可是對接過程當中總會遇到這樣那樣的問題,好比屏幕閃爍、旋轉不生效、狀態欄消失等等一系列使人噁心的bug。筆者負責的項目,屬於Reactnative&&ObjectC混合開發模式,目前的須要須要主app默認豎向展現,同時提供給Reactnative一個支持自動橫豎屏的ViewController。特此針對iOS屏幕旋轉進行了整理概括,望對各位開發者有所幫助。小程序
//Portrait 表示縱向,Landscape 表示橫向。
typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
UIDeviceOrientationUnknown,
// Device oriented vertically, home button on the top
UIDeviceOrientationPortraitUpsideDown,
// Device oriented horizontally, home button on the right
UIDeviceOrientationLandscapeLeft,
// Device oriented horizontally, home button on the left
UIDeviceOrientationLandscapeRight,
// Device oriented flat, face up
UIDeviceOrientationFaceUp,
// Device oriented flat, face down
UIDeviceOrientationFaceDown
} __TVOS_PROHIBITED;
複製代碼
獲取當前屏幕的方法:[UIDevice currentDevice].orientation
複製代碼
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onDeviceOrientationDidChange)
name:UIDeviceOrientationDidChangeNotification
object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
監聽方法實現
- (BOOL)onDeviceOrientationDidChange{
//獲取當前設備Device
UIDevice *device = [UIDevice currentDevice] ;
//識別當前設備的旋轉方向
switch (device.orientation) {
case UIDeviceOrientationFaceUp:
NSLog(@"屏幕幕朝上平躺");
break;
case UIDeviceOrientationFaceDown:
NSLog(@"屏幕朝下平躺");
break;
case UIDeviceOrientationUnknown:
//系統當前沒法識別設備朝向,多是傾斜
NSLog(@"未知方向");
break;
case UIDeviceOrientationLandscapeLeft:
NSLog(@"屏幕向左橫置");
break;
case UIDeviceOrientationLandscapeRight:
NSLog(@"屏幕向右橫置");
break;
case UIDeviceOrientationPortrait:
NSLog(@"屏幕直立");
break;
case UIDeviceOrientationPortraitUpsideDown:
NSLog(@"屏幕直立,上下顛倒");
break;
default:
NSLog(@"沒法識別");
break;
}
return YES;
}
複製代碼
// Note that UIInterfaceOrientationLandscapeLeft is equal to UIDeviceOrientationLandscapeRight (and vice versa).
// This is because rotating the device to the left requires rotating the content to the right.
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
UIInterfaceOrientationUnknown = UIDeviceOrientationUnknown,
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
} __TVOS_PROHIBITED;
複製代碼
爲了達到頁面的流暢效果
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
複製代碼
支持多種頁面旋轉方向bash
typedef NS_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),
} __TVOS_PROHIBITED;
複製代碼
//方法1
- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
//方法2
- (UIInterfaceOrientationMask)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
// Returns interface orientation masks.
//方法3
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;!
複製代碼
方法1:頁面是否支持自動旋轉
方法2:頁面支持的旋轉方向有哪些
方法3:頁面優先展現的旋轉方向
複製代碼
//1.決定當前界面是否開啓自動轉屏,若是返回NO,後面兩個方法也不會被調用,只是會支持默認的方向
- (BOOL)shouldAutorotate {
return YES;
}
//2.返回支持的旋轉方向
//iPad設備上,默認返回值UIInterfaceOrientationMaskAllButUpSideDwon
//iPad設備上,默認返回值是UIInterfaceOrientationMaskAll
- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
//3.返回進入界面默認顯示方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
複製代碼
在程序界面經過點擊等方式切換到橫屏微信
// 方法1:
- (void)setInterfaceOrientation:(UIDeviceOrientation)orientation {
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:orientation]
forKey:@"orientation"];
}
}
//方法2:
- (void)setInterfaceOrientation:(UIInterfaceOrientation)orientation {
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice
instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
int val = orientation;
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
}
複製代碼
- Xcode的General設置
- Xcode的nfo.plist設置
- 代碼設置Appdelegete中
複製代碼
工程Target屬性配置(全局權限) > Appdelegate&&Window > 根視圖控制器> 普通視圖控制器
複製代碼
【General】—>【Deployment Info】—>【Device Orientation】
值得注意的是,對於iPhone,若是四個屬性咱們都選或者都不選,效果和默認的狀況同樣
複製代碼
Supported interface orientation
與第一種方式同樣的效果,兩種方式最終都是設置info.plist中的屬性
複製代碼
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
}
複製代碼
若是咱們實現了Appdelegate的這一方法,那麼咱們的App的全局旋轉設置將以這裏的爲準,即便前兩種方法的設置與這裏的不一樣。app
開發中常涉及到的控制器ide
UITabbarViewController,UINavigationBarController ,UIViewController
複製代碼
咱們的項目都是用UITabbarViewController做爲Window的根視圖控制器,而後管理着若干個導航控制器UINavigationBarController,再由導航欄控制器去管理普通的視圖控制器UIViewController。若以此爲例的話,關於旋轉的優先級從高到低就是UITabbarViewController>UINavigationBarController >UIViewController了。若是具備高優先級的控制器關閉了旋轉設置,那麼低優先級的控制器是沒法作到旋轉的。函數
好比說咱們設置要單個視圖控制器能夠自動旋轉,這須要在視圖控制器中增長shouldAutorotate方法返回YES或者NO來控制。但若是存在上層根視圖控制器,而咱們只在這個視圖控制器中實現方法,會發現這個方法是不走的,由於這個方法被上層根視圖控制器攔截了學習
//是否自動旋轉
-(BOOL)shouldAutorotate{
return self.selectedViewController.shouldAutorotate;
}
//支持哪些屏幕方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return [self.selectedViewController supportedInterfaceOrientations];
}
//默認方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}
複製代碼
//是否自動旋轉
//返回導航控制器的頂層視圖控制器的自動旋轉屬性,由於導航控制器是以棧的緣由疊加VC的
//topViewController是其最頂層的視圖控制器,
-(BOOL)shouldAutorotate{
return self.topViewController.shouldAutorotate;
}
//支持哪些屏幕方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return [self.topViewController supportedInterfaceOrientations];
}
//默認方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
複製代碼
其實就是高優先級的視圖控制器要跟隨低優先級控制器的旋轉配置。這樣就可以達到目的優化
使用模態視圖能夠不受這種根視圖控制器優先級的限制。這個也很容易理解,模態彈出的視圖控制器是隔離出來的,不受根視圖控制的影響。具體的設置和普通視圖器代碼相同
複製代碼
App主要主界面豎向展現,部分頁面橫向展現動畫
兩種解決方案ui
1.開啓全局權限設置項目支持的旋轉方向
2.自定義標籤控制器和導航控制器來設置屏幕的自動旋轉。
3.自定義基類控制器設置不支持自動轉屏,並默認只支持豎屏
4.對項目中須要轉屏幕的控制器開啓自動轉屏、設置支持的旋轉方向並設置默認方向
複製代碼
1.在Applegate文件中增長一個用於記錄當前屏幕是否橫屏的屬性
2.須要橫屏的界面,進入界面後強制橫屏,離開界面時恢復豎屏
複製代碼
一、添加監聽
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onDeviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification
object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
二、實現監聽
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if (_allowAutoRotate) {
//只支持橫屏
return UIInterfaceOrientationMaskLandscape;
}else{
//支持豎屏
return UIInterfaceOrientationMaskPortrait;
}
}
三、頁面控制
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
delegate.allowAutoRotate = YES;
//進入界面:設置橫屏
[self setDeviceInterfaceOrientation:UIDeviceOrientationLandscapeLeft];
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
delegate.allowAutoRotate = NO;
//離開界面:設置豎屏
[self setDeviceInterfaceOrientation:UIDeviceOrientationPortrait];
}
複製代碼
當前viewController達到預期效果,可是在返回上一頁時,或者在當前頁面不不支持的方向的上一頁進來時,不能當即達到預期狀態,須要設備方向更換一次才能恢復正常
#pragma mark -UITabBarControllerDelegate
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
[self presentViewController:[UIViewController new] animated:NO completion:^{
[self dismissViewControllerAnimated:NO completion:nil];
}];
}
#pragma mark -UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
[self presentViewController:[UIViewController new] animated:NO completion:^{
[self dismissViewControllerAnimated:NO completion:nil];
}];
}
複製代碼
可是會出現屏幕閃爍問題,不推薦使用此方案,能夠經過強制設置屏幕方向,在視圖的鉤子函數中進行手動控制
//設置樣式
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
//設置是否隱藏
- (BOOL)prefersStatusBarHidden {
// [super prefersStatusBarHidden];
return NO;
}
//設置隱藏動畫
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
return UIStatusBarAnimationNone;
}
複製代碼
原文連接: tech.meicai.cn/detail/83, 也可微信搜索小程序「美菜產品技術團隊」,乾貨滿滿且每週更新,想學習技術的你不要錯過哦。