前言
去年的时候有一个项目需求,其中单个控制器跳转进去横屏,其他控制器保持横屏,当初做的时候觉得很简单,找了下API用模拟器试了下没问题就没当回事,后来真机测试的时候傻眼了,模拟器可以通过测试,真机有时候能横屏有的时候不行,而且有时候进入横屏的时候也会布局错乱,在网上找了许多demo都没有好的办法,后来借鉴群里大神的demo算是完美实现了横屏,可以大神用的语言是swift.项目时间紧当时也没有总结,现在刚好有空把项目找出来把里面的代码剥出来,这里暂时只讨论present实现横屏.
坑
- 模拟器能够横屏,真机偶尔不能横屏
- 进去控制器能横屏,返回之前的控制器还是横屏
- 进去控制器是横屏,锁定屏幕解锁之后返回上个控制还是横屏
API
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
UIInterfaceOrientation
视图的方向,他和statusBar的方向是一致的
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
/** 未知方向 */
UIInterfaceOrientationUnknown = UIDeviceOrientationUnknown,
/** 竖直 */
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
/** 上下翻转 */
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
/** 向左旋转 */
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
/** 向右旋转 */
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
} __TVOS_PROHIBITED;
UIDeviceOrientation与UIInterfaceOrientation是两个互不相干的属性。
其中一个并不会随另外一个变化而变化。但大多数情况下,两者会一起出现,主要是为了达到视觉的统一。
注意:
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
两者是相反的
UIInterfaceOrientationMask
这是ios6之后新增的一组枚举值,使用组合时更加方便,使用时根据返回值类型选择正确的格式,避免可能出现的bug
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),
如果想横屏在Targets应该去勾选对应的选项
image.png
想让控制切换横竖屏主要是这三个方法
/** Interface的方向是否会跟随设备方向自动旋转,如果返回NO,后两个方法不会再调用 */
- (BOOL)shouldAutorotate {
return YES;
}
/** 返回直接支持的方向 */
- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
return 返回你想要的方向;
}
/** 返回最优先显示的屏幕方向 */
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return 返回你想要的方向;
}
注意:如果在targets中只设置了竖屏那么方法preferredInterfaceOrientationForPresentation和supportedInterfaceOrientations无效
代码
在要横屏的控制器写下面的方法
- (BOOL)shouldAutorotate {
return NO;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeRight;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeRight;
}
加入一个返回的事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self dismissViewControllerAnimated:YES completion:nil];
}
接下来看效果
Untitled.gif
看似好像解决了问题,其实并没有,在进入横屏页锁屏再解锁返回上个控制器就会出现布局错误
原因是返回上一页时,或者在当前页面不不支持的方向的上一页进来时,不能立即达到预期状态,需要设备方向更换一次才能恢复正常。
这是在dismis返回之前加入以下代码强制设置设备为竖屏即可解决问题
NSNumber *orientationUnknown = [NSNumber numberWithInt:UIInterfaceOrientationUnknown];
[[UIDevice currentDevice] setValue:orientationUnknown forKey:@"orientation"];
NSNumber *orientationTarget = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:orientationTarget forKey:@"orientation"];
网友评论