iOS - 强制横屏
一、正常方向旋转处理流程
要求旋转方向-》判断是否支持该方向-》判断是否支持旋转
注释:下文将“要求旋转的方向”称为pending方向。
1、判断支持的方向
系统会调用两个方法:
AppDelegate的application:supportedInterfaceOrientationsForWindow:(如果没有实现,info.plist中的Supported interface orientations作为代替) 当前视图控制器的supportedInterfaceOrientations(默认实现是除了向上的三个方向)
两个方法的重叠部分是支持的方向(有可能没有重叠的方向)。
注释:当前视图控制器指的是哪个? 举例: rootvc:nav-(push)->child1=》当前视图控制器为nav rootvc:nav-(push)->child1-(presented by child1)->child2=》当前视图控制器为child2 rootvc:nav-(push)->child1-(presented by nav)->child2=》当前视图控制器为child2
2、判断是否支持旋转
支持旋转:
如果有重叠的方向-》旋转;
如果没有重叠的方向-》崩溃
不支持旋转:有没有重叠的方向,都不旋转。
判断是否支持旋转的方法是当前视图控制器的shouldAutorotate
注意:如果得到的重叠的方向是竖屏,并且支持旋转,但是,要求旋转的方向是横屏,也会旋转到横屏方向。
二、触发方向旋转
- 用户旋转屏幕方向(方向锁没有锁),这是正常的方式;
- KVC的方式修改currentDevice的orientation属性,强制横屏就是使用的这个方式。
三、另当别论的modal动画
使用模态动画展示出来的视图控制器,展示时,系统会调用preferredInterfaceOrientationForPresentation方法,即使不使用上述两种方法旋转屏幕方向,一样可以达到旋转屏幕的效果(当然是在preferredInterfaceOrientationForPresentation的结果与当前屏幕方向不同的情况下)
四、键盘
键盘方向是preferredInterfaceOrientationForPresentation的结果,preferredInterfaceOrientationForPresentation默认是竖屏。
五、进入应用时,什么决定横竖屏
支持的方向只有横屏时,才横屏,不然都先竖屏,之后再根据屏幕方向,会旋转屏幕或者继续竖屏。
六、iOS系统不同版本兼容
没有研究iOS7的系统,只处理了iOS8和9的兼容问题。
iOS8下,使用push动画,如果使用第二种方法旋转屏幕不生效的话,可以在旋转之后,present一个横屏的空白视图控制器,再立即dismiss。
七、我的产品需求
阅读类应用:
- 书架在内的绝大部分页面,只支持竖屏;
- 阅读器是使用push动画展示的,支持横屏;
- 从阅读器可以继续push出来设置、目录、搜索页面等,这些页面的方向与阅读器一致;
- 搜索页面需要弹出键盘;
- 设置页展示期间,可能需要present其他视图控制器,方向也与阅读器一致
实现方式:
- info.plist里怎么设置方向都可以
- AppDelegate中application:supportedInterfaceOrientationsForWindow:返回所有方向;
- 除阅读器外的其它视图控制器,shouldAutorotate返回NO,supportedInterfaceOrientations返回竖屏;
- 阅读器中shouldAutorotate返回YES;
- 进入阅读器时,supportedInterfaceOrientations返回竖屏,如果需要横屏的话,在viewDidAppear中延时0.2秒调用旋转屏幕,并将supportedInterfaceOrientations中的返回值改为横屏;
代码示例:
1 AppDelegate.m 2 3 - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { 4 return UIInterfaceOrientationMaskAll; 5 }
除阅读器外的视图控制器
1 BaseViewController.m 2 3 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { 4 return UIInterfaceOrientationMaskPortrait; 5 } 6 7 - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { 8 return UIInterfaceOrientationPortrait; 9 } 10 11 - (BOOL)shouldAutorotate { 12 return NO; 13 }
阅读器
1 BookReaderVC.m 2 3 - (void)viewDidAppear:(BOOL)animated { 4 [super viewDidAppear:animated]; 5 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 6 [self forceScreenDirectionToPortrait:YES]; 7 }); 8 } 9 10 - (void)forceScreenDirectionToPortrait:(BOOL)toPortrait { 11 if (toPortrait) { 12 self.orientation = UIInterfaceOrientationMaskPortrait; 13 [[UIDevice currentDevice] setValue:@(UIDeviceOrientationLandscapeRight) forKey:@"orientation"]; 14 [[UIDevice currentDevice] setValue:@(UIDeviceOrientationPortrait) forKey:@"orientation"]; 15 } else { 16 self.orientation = UIInterfaceOrientationMaskLandscapeRight; 17 [[UIDevice currentDevice] setValue:@(UIDeviceOrientationPortrait) forKey:@"orientation"]; 18 [[UIDevice currentDevice] setValue:@(UIDeviceOrientationLandscapeRight) forKey:@"orientation"]; 19 if (!IOS9_OR_LATER) { 20 UIViewController *blankVC = [[UIViewController alloc] init]; 21 blankVC.view.backgroundColor = [UIColor clearColor]; 22 [self presentViewController:blankVC animated:NO completion:nil]; 23 [blankVC dismissViewControllerAnimated:NO completion:nil]; 24 } 25 } 26 } 27 28 - (BOOL)shouldAutorotate { 29 return YES; 30 } 31 32 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { 33 return self.orientation; 34 }
需要弹出键盘的视图控制器
1 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { 2 UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; 3 if (UIInterfaceOrientationIsLandscape(orientation)) { 4 return UIInterfaceOrientationMaskLandscapeRight; 5 } else { 6 return UIInterfaceOrientationMaskPortrait; 7 } 8 }