iOS转屏

iOS提供了在设备旋转时,界面显示发生相应适配的能力,已达到方便用户使用并提供最佳显示效果的目的。开发者需要指定应用支持的显示方向,并对界面显示做出对应的适配。

现在的app绝大部分都是从iOS7开始支持了,所以iOS6之前的转屏不在本文的考虑范围
一、两种旋转方向
1. 设备方向(device orientation)
2. UI显示的方向
iOS提供了在设备旋转时,界面显示发生相应适配的能力,以达到方便用户使用并提供最佳显示效果的目的。开发者需要指定应用支持的显示方向,并对界面显示做出对应的适配。由于界面适配的工作量相当大,目前国内的应用大都只支持默认的竖屏方向。
二、相关的旋转方向枚举
1. iOS 5和之前版本:

typedef NS_ENUM(NSInteger, UIInterfaceOrientation) { 
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait, 
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown, 
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight, 
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft 
}; 
  1. iOS 6和之后版本新增了
 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), 
}; 

iOS 6及以后的版本使用 NS_OPTIONS 的方式重新定义了UIInterfaceOrientationMaskPortrait、UIInterfaceOrientationMaskLandscapeLeft、UIInterfaceOrientationMaskLandscapeRight、UIInterfaceOrientationMaskPortraitUpsideDown几种基础枚举,这就意味着能以组合的方式更加方便的使用这些枚举值。
三、控制转屏的相关方法
1. iOS6及以后实现转屏的方法如下:

- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0); 
- (NSUInteger)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0); 
// Returns interface orientation masks. 
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0); 

第一个方法决定是否支持多方向旋转屏,如果返回NO则后面的两个方法都不会再被调用,而且只会支持默认的UIInterfaceOrientationMaskPortrait方向;

第二个方法直接返回支持的旋转方向,该方法在iPad上的默认返回值是UIInterfaceOrientationMaskAll,iPhone上的默认返回值是UIInterfaceOrientationMaskAllButUpsideDown,详情见官方Q&A文档;

第三个方法返回最优先显示的屏幕方向,比如同时支持Portrait和Landscape方向,但想优先显示Landscape方向,那软件启动的时候就会先显示Landscape,在手机切换旋转方向的时候仍然可以在Portrait和Landscape之间切换;
2. attemptRotationToDeviceOrientation方法

+ (void)attemptRotationToDeviceOrientation NS_AVAILABLE_IOS(5_0);

这个方法从iOS5开始就支持了,使用场景是 interface orientation和device orientation 不一致,但希望通过重新指定 interface orientation 的值,立即实现二者一致;如果这时只是更改了支持的 interface orientation 的值,没有调用attemptRotationToDeviceOrientation,那么下次 device orientation 变化的时候才会实现二者一致,关键点在于能不能立即实现。

举个例子:
假设当前的 interface orientation 只支持 Portrait,如果 device orientation 变成 Landscape,那么 interface orientation 仍然显示 Portrait;

如果这时我们希望 interface orientation 也变成和 device orientation 一致的 Landscape,以iOS 6 为例,需要先将 supportedInterfaceOrientations 的返回值改成Landscape,然后调用 attemptRotationToDeviceOrientation方法,系统会重新询问支持的 interface orientation,已达到立即更改当前 interface orientation 的目的
四、如何决定interface orientation
1. 全局控制
Info.plist文件中,有一个Supported interface orientations,可以配置整个应用的屏幕方向,此处为全局控制
2. UIWindow
iOS6的UIApplicationDelegate提供了下述方法,能够指定 UIWindow 中的界面的屏幕方向:

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window

该方法默认值为 Info.plist 中配置的 Supported interface orientations 项的值。

iOS中通常只有一个 window,但是如果是视频播放类的app,很有可能会有两个或多个window。所以做这类app开发的同学要多注意这个方法。
3. controller
只有以下两种情况:
当前controller是window的rootViewController
当前controller是modal模式的时,orientations相关方法才会起作用(才会被调用),当前controller及其所有的childViewController都在此作用范围内。
4. 最终支持的屏幕方向
前面所述的3种控制规则的交集就是一个controller的最终支持的方向
如果最终的交集为空,在iOS6以后会抛出UIApplicationInvalidInterfaceOrientationException崩溃异常。
四、强制屏幕旋转
如果interface和device方向不一样,想强制将interface旋转成device的方向,可以通过attemptRotationToDeviceOrientation实现,但是如果想将interface强制旋转成任一指定方向,该方式就无能为力了。

不过聪明的开发者们总能想到解决方式:
1、私有方法

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait]; 

做越狱开发的同学,可以使用这个方法
2、旋转view的transform
也可以通过旋转view的transform属性达到强制旋转屏幕方向的目的,但个人感觉这不是靠谱的思路,可能会出现一些特别神奇的bug。
3、主动触发 orientation 机制
要是能主动触发系统的 orientation 机制,调用 orientation 相关方法,使新设置的 orientation 值起作用就好了。这样只要提前设置好想要支持的 orientation,然后主动触发 orientation 机制,便能实现将 interface orientation旋转至任意方向的目的。
万能的stackoverflow上提供了一种主动触发的方式:

iOS 6及以后:

UIViewController *vc = [[UIViewController alloc]init]; 
[self presentModalViewController:vc animated:NO]; 
[self dismissModalViewControllerAnimated:NO]; 
[vc release]; 

这种方式会触发UIKit重新调用controller的orientation相关方法,以达到在device方向不变的情况下改变interface方向的目的。
只能说这种方法很二,很二,但是,只能凑合着用吧。有知道更好方法的同学可以补充一下。
PS:
话说iOS8中的屏幕旋转相关方法又变化了,表示适配起来很头疼。
五、参考文档
Why won’t my UIViewController rotate with the device?
How to force a UIViewController to Portait orientation in iOS 6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值