前言
iOS的屏幕旋转可谓让人摸不着头脑,其中有历史原因也有设计原因。为了用户体验却大大增加了我们的开发难度。接下来聊聊屏幕旋转的坑。
大前提
iOS系统中,下拉控制台里有一个圆形锁,打开这个锁可以强制锁定屏幕旋转的方向。如果用户打开了这个圆形锁。无论你的App支持几个方向的旋转,都无法响应设备方向改变。
所以思路一下就清晰了。屏幕旋转总共两种情况
- 用户没有打开锁定功能,手机物理旋转的时候,响应重力感应带来的屏幕旋转。
- 用户打开了锁定功能,手机不响应重力感应带来的屏幕旋转
第一步设置App支持的方向
在开始一个工程,我们需要考虑到视图旋转是不是在整个App中都是全局支持的,以及支持的方向。例如有些iPad应用,支持全局的旋转视图。另外一种情况是,大多数时候我们只需要在某些页面,例如视频播放页面,去支持旋转。
全局设定支持的旋转页面有两种方法,第一种在工程设置里面,Device Orientantion中勾选支持的方向。
或者在AppDeleagate中用代码设置
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
//返回你的app支持的旋转方向。
return XXX ;
}
具体实现
完成第一步的基本设置以后,我们根据之前提到过的两种情况来考虑具体的实现。
第一种情况,用户未开启锁定
用户在没有锁定的情况下,此时设备物理旋转后,App中会得到反馈。
收到一个旋转屏幕的通知:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onDeviceOrientationChange)
name:UIDeviceOrientationDidChangeNotification
object:nil];
此时我们可以在通知回调里面去做响应的布局修改,适应横屏模式。
但现实中很多时候需求并不是这么简单。在iPhone上,大部分的App的大部分的页面并不支持旋转,而是在特定的页面,根据需要去旋转。
这个需求前提前面的设置只支持Portrait,
此时我们要通过在controller中重写以下几个方法,来绕过设置,在特定的页面去修改屏幕旋转的方向。
- (BOOL)shouldAutorotate {
//确定你的控制器是否能够旋转(手动控制,或者自动旋转都要Return YES)
return YES;
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
- (NSUInteger)supportedInterfaceOrientations {
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
#endif
//返回你的屏幕支持的方向
return XXX;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
//你跳转(present)到这个新控制器时,按照什么方向初始化控制器
return XXX;
}
也就是在特定的我们想让他能够旋转的页面中,去重写以上方法。
第三个方法可根据需要重写。
紧接着,这里有一个坑:当前页面的是否旋转,并不取决于当前页面的这三个方法(23333)
因为当前页面是否能够旋转,取决于window的root控制器,比如navigationcontroller,tabbarcontroller,
所以,来到window的root控制器中,去重写方法,记得根据实际情况做好判断,不然此控制器下的所有子页面就都支持旋转了。(2333)
也有另外一个方法就是通过category的形式,对navigationcontroller和tabbarcontroller进行扩展。
二者选其一吧,都能达到相同的目的。
到此,这种情况下,用户没有锁定,设备物理旋转,接受接收通知,响应旋转,实现,就完成。
第二种情况用户开启了锁定
事实上这种情况下,设备的物理旋转,App已经无法收到反馈,也就是你就算重写了那几个方法,也无法响应设备的旋转。
在这种情况下,我们就需要手动去旋转App的方向。
前提还是根据之前的重写那几个方法。
这是手动强制旋转的方法,私有API,但是商店能够过审,简直神奇。
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 = UIInterfaceOrientationLandscapeRight;//这个方向即需要旋转到的那个方向,自行设置
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
同样的,在改变了屏幕方向以后,收到通知,然后做响应的操作即可。
总结
事实上,旋转存在的坑并不难,根据实际需求来做出修改是我们活学活用的目的。
网友评论