iOS16横竖屏的切换有了新的方式,正好赶上新的项目要求,所以重新整理了一下项目中的横竖屏切换问题。
项目要求:
- iPhone整体禁止屏幕旋转只能竖屏,某些特定页面强制横屏,某些页面可以自由旋转。
- iPad整体可以自由旋转,某些页面可以强制切换横竖屏,且切换后当前页面关闭自由旋转,返回后开启自由旋转。
如何开始横竖屏切换
1、项目配置:
在Xcode中TARGETS - General - Deployment Info
中设置支持的方向,例如iPhone设置只支持竖屏,iPad支持全方向,注意iPad情况下需要勾选Requires full screen
,设置为全屏,不分屏,否则强制切换屏幕旋转将失效(自己发现的,没有找到相关解释,有大神也可以解释一下)。如果不配置,只通过AppDelegate
中代理方法控制,会导致启动页时不能正常识别屏幕方向。
2、AppDelegate
中的设置
因为某些页面需要强制屏幕切换,所以通过在AppDelegate
实现代理的方式控制.
AppDelegate.h
中
/// 通过AppDelegate是实现旋转,解决部分页面强制旋转
/// 屏幕支持的方法方向
@property (nonatomic, assign) UIInterfaceOrientationMask orientations;
AppDelegate.m
中
- 在
application:didFinishLaunchingWithOptions:
中设置默认方向
// 设置默认方向
if (isPad) {
// ipad
self.orientations = UIInterfaceOrientationMaskAll;
} else {
self.orientations = UIInterfaceOrientationMaskPortrait;
}
- 实现代理方法
/// 切换横竖屏:返回支持方向
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return self.orientations;
}
- 强制切换方向,且切换后禁止旋转
例如强制横屏如下
// AppDelegate设置横屏
AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
// 当前是否横屏
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft || [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) {
// 已经横屏,AppDelegate中锁定为当前屏幕状态
app.orientations = (1 << [UIApplication sharedApplication].statusBarOrientation);
} else {
// 竖屏-强制屏幕横屏
// AppDelegate中锁定为横屏
app.orientations = UIInterfaceOrientationMaskLandscapeRight;
// 强制旋转
if (@available(iOS 16.0, *)) {
#if defined(__IPHONE_16_0)
// 避免没有更新Xcode14的同事报错
// iOS16新API,让控制器刷新方向,新方向为上面设置的orientations
[self setNeedsUpdateOfSupportedInterfaceOrientations];
#endif
} else {
// iOS16以下
NSNumber *orientationPortrait = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight];
[[UIDevice currentDevice] setValue:orientationPortrait forKey:@"orientation"];
}
}
在适当的位置记得iPhone修正方向,iPad放开旋转
// iPhone改为竖屏,具体方式参考横屏
// pad放开屏幕方向
AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
app.orientations = UIInterfaceOrientationMaskAll;
- 某个页面放开横竖屏切换,比如全屏视频播放时。
// 放开
AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
app.orientations = UIInterfaceOrientationMaskAll;
// 锁定
AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
app.orientations = UIInterfaceOrientationMaskPortrait;
#这种情况下,iOS16的强制横竖屏切换需要添加代码设置强制旋转,例如:
// 强制屏幕竖屏:手机
if ([UIApplication sharedApplication].statusBarOrientation != UIInterfaceOrientationPortrait) {
if (@available(iOS 16.0, *)) {
// iOS16新API,让控制器刷新方向,新方向为上面设置的orientations
#if defined(__IPHONE_16_0)
[self setNeedsUpdateOfSupportedInterfaceOrientations];
NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
UIWindowScene *scene = [array firstObject];
// 屏幕方向
UIInterfaceOrientationMask orientation = UIInterfaceOrientationMaskPortrait;
UIWindowSceneGeometryPreferencesIOS *geometryPreferencesIOS = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:orientation];
// 开始切换
[scene requestGeometryUpdateWithPreferences:geometryPreferencesIOS errorHandler:^(NSError * _Nonnull error) {
NSLog(@"强制%@错误:%@", @"横屏", error);
}];
#endif
} else {
// iOS16以下
NSNumber *orientationPortrait = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:orientationPortrait forKey:@"orientation"];
}
}
- 关于横竖屏切换的监听
对于屏幕旋转的监听,建议监听UIApplicationDidChangeStatusBarOrientationNotification
,及状态栏的方向变化通知,这个收到这个通知的时候说明页面UI已经切换了。例如:
// 横竖屏切换通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleScreenOrientationChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
/// 横竖屏切换通知
- (void)handleScreenOrientationChange:(NSNotification *)noti {
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait || [UIApplication sharedApplication].statusBarOrientation == UIDeviceOrientationPortraitUpsideDown) {
// 竖屏
} else {
// 横屏
}
}
注意判断屏幕方向的时候一定要用UIInterfaceOrientation:屏幕的方向,不要错误的使用的UIDeviceOrientation:设备的方向。
暂时就这些内容。
补充一点,写代码的时候能用Autolayout就尽量用,不然突然有一天让你整个App适配横竖屏切换,在原有手机端代码基础上开发Pad,还有分屏效果,哭都没地方。