本文为CocoaChina网友南华coder投稿
前文链接:代码处理iOS的横竖屏旋转(上)
三、屏幕旋转方向下的视图处理
1、屏幕旋转时,建议监听UIApplicationDidChangeStatusBarOrientationNotification
原因1:supportedInterfaceOrientations方法中最终返回的是多个界面方向。
原因2(最重要的原因):我们真正要处理的是页面方向发生旋转UI的变化。而在设备的物理方向发生旋转的时候,如果此时当前控制器的页面并没有旋转,我们这时改变UI布局,可能就发生问题了。
2、屏幕的宽高处理
1)在iOS 8之后,当屏幕旋转的时候,[[UIScreen mainScreen] bounds]也发生了改变。如横屏时候的屏幕宽度 其实是竖屏的时候屏幕的高度。
2)我们处理视图布局时候,如果使用到屏幕的宽高,不要直接使用SCREEN_HEIGHT和SCREEN_WIDTH,而使用SCREEN_MIN和SCREEN_MAX
#define SCREEN_HEIGHT CGRectGetHeight([[UIScreen mainScreen] bounds]) #define SCREEN_WIDTH CGRectGetWidth([[UIScreen mainScreen] bounds]) #define SCREEN_MIN MIN(SCREEN_HEIGHT,SCREEN_WIDTH) #define SCREEN_MAX MAX(SCREEN_HEIGHT,SCREEN_WIDTH)
说明:竖屏时候,宽是SCREEN_MIN,高是SCREEN_MAX;横屏时候,宽是SCREEN_MAX,高是SCREEN_MIN。
3、屏幕旋转下处理Demo
//监听UIApplicationDidChangeStatusBarOrientationNotification的处理 - (void)handleStatusBarOrientationChange: (NSNotification *)notification{ UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation]; BOOL isLandscape = NO; switch (interfaceOrientation) { case UIInterfaceOrientationUnknown: NSLog(@"未知方向"); break; case UIInterfaceOrientationPortrait: case UIInterfaceOrientationPortraitUpsideDown: isLandscape = NO; break; case UIInterfaceOrientationLandscapeLeft: case UIInterfaceOrientationLandscapeRight: isLandscape = YES; break; default: break; } if (isLandscape) { self.tableView.frame = CGRectMake(0, 0, SCREEN_MAX, SCREEN_MIN - 44); }else{ self.tableView.frame = CGRectMake(0, 0, SCREEN_MIN, SCREEN_MAX - 64); } [self.tableView reloadData]; }
说明:当然也可以选择使用Masonry这样优秀的AutoLayout布局第三方库来处理,storyBoard来布局次之。
4、屏幕旋转下处理Demo效果图
竖屏下效果.png
横屏下效果.png
5、屏幕旋转处理的建议
1)旋转前后,view当前显示的位置尽量不变
2)旋转过程中,暂时界面操作的响应
3)视图中有tableview的话,旋转后,强制 [tableview reloadData],保证在方向变化以后,新的row能够充满全屏。
四、强制横屏
APP中某些页面,如视频播放页,一出现就要求横屏。这些横屏页面或模态弹出、或push进来。
1、模态弹出ViewController情况下 强制横屏的设置
//QSShow3Controller.m - (BOOL)shouldAutorotate{ return NO; } - (UIInterfaceOrientationMask)supportedInterfaceOrientations{ return UIInterfaceOrientationMaskLandscapeRight; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{ return UIInterfaceOrientationLandscapeRight; } //模态弹出 QSShow3Controller *vc = [[QSShow3Controller alloc]init]; [self presentViewController:vc animated:YES completion:nil];
说明:这种情况比较简单处理。
2、push推入ViewController情况下 强制横屏的设置
//QSShow4Controller.m -(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self setInterfaceOrientation:UIInterfaceOrientationLandscapeRight]; } //强制转屏(这个方法最好放在BaseVController中) - (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]]; // 从2开始是因为前两个参数已经被selector和target占用 [invocation setArgument:&orientation atIndex:2]; [invocation invoke]; } } //必须返回YES - (BOOL)shouldAutorotate{ return YES; } - (UIInterfaceOrientationMask)supportedInterfaceOrientations{ return UIInterfaceOrientationMaskLandscapeRight; } //Push推入 QSShow4Controller *vc = [[QSShow4Controller alloc]init]; [self.navigationController pushViewController:vc animated:YES];
说明:苹果不允许直接调用setOrientation方法,否则有被拒的风险;使用NSInvocation对象给[UIDevice currentDevice]发消息,强制改变设备方向,使其页面方向对应改变,这是苹果允许的。
五、其他
1、 APP启动时,手机横屏下,首页UI(该页面只支持竖屏)出错(add by 2017/6/20)
//设置设置状态栏竖屏 [[UIApplication sharedApplication]setStatusBarOrientation:UIInterfaceOrientationPortrait];
以上详细源码参考:QSRotationScreenDemo