iOS 横竖屏切换解决方案

iOS 横竖屏切换解决方案

前言

在大多数项目中,App 的 UI 方向都是竖屏的,所以一般会在 target 中将屏幕方向设置为只支持竖屏。如下图

image

而在项目中可能又存在少量的横屏页面,或少数支持多方向的页面。视频播放页,通常都支持自动旋转。在我的项目中就出现这种情况,为了解决这个问题,所以对 UIViewController 进行了分类扩展。

方案使用

效果

image

默认情况下是竖屏转动手机,不跟随旋转,实现支持方向方法后,可以跟随。

Demo链接地址: 前往

引入

使用 Cocoapods

pod 'AutoRotation'

手动

前往项目地址,下载之后将 AutoRotation 文件夹中的文件拖到项目中即可

配置

将工程设置为只支持竖屏,如图

image

使用

由于项目中绝大多数页面都是竖屏的,所以默认情况下,所有的 Controller 将是竖屏展示。在需要横屏或多方向的 Controller 中实现代码如下:

#import <AutoRotation/AutoRotation.h>
// 或
#import "AutoRotation.h"

// ViewController.m 中实现下面方法
- (UIInterfaceOrientationMask)ar_supportedOrientations {
    // 支持三个方法
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

通过实现上述方法,即可让特定的 Controller 支持设定的方向。

其它 API

/// 转到指定方向
- (void)ar_turnToOrientation:(UIInterfaceOrientationMask)orientation;
/// 转为竖屏
- (void)ar_turnToPortrait;
/// 转为横屏
- (void)ar_turnToLandscape;
/// 添加特殊处理Controller,用于处理如 AlertContoller 等情况
+ (void)ar_addSpecialControllers:(NSArray<NSString *> *)controllers;
/// 移除特殊处理Controller
+ (void)ar_removeSpecialControllers:(NSArray<NSString *> *)controllers;

解决思路

  1. 使用 Runtime 交互 Appdelegate 和 UIViewController 的相关方法
  2. 获取当前可见的顶部 Controller 的方法
  3. 将顶部 Controller 支持的方向返回给 Appdelegate 中的 application:supportedInterfaceOrientationsForWindow:方法
  4. 显示出对应用的方向

实现思路其实比较简单,当然中途会有一些问题,代码实现中对一些异常情况进行了处理。

屏幕方向枚举

iOS 中关于方向的枚举有三种

UIInterfaceOrientationMask

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),
} __TVOS_PROHIBITED;

UIInterfaceOrientation

typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
    UIInterfaceOrientationUnknown            = UIDeviceOrientationUnknown,
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
} __TVOS_PROHIBITED;

UIDeviceOrientation

typedef NS_ENUM(NSInteger, 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
} __TVOS_PROHIBITED;

手动更改屏幕方向

由于方案中并不更改工程设置,只勾选了竖屏,所以在实现中使用了手动转屏方法。代码如下:

+ (BOOL)setOrientation:(UIInterfaceOrientationMask)orientation {
    UIInterfaceOrientation interfaceOrientation = [self getOrientationWithOrientationMask:orientation];
    UIInterfaceOrientation currentOrientation = [UIViewController currentOrientation];
    if (currentOrientation == interfaceOrientation) {
        return NO;
    }
    NSLog(@"ar log: interfaceOrientation:%ld", interfaceOrientation);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    [[UIApplication sharedApplication] setStatusBarOrientation:interfaceOrientation animated:NO];
#pragma clang diagnostic pop
    [[UIDevice currentDevice] setValue:@(interfaceOrientation) forKey:@"orientation"];
    return YES;
}

实现

通过上述的基础及实现思路铺垫,总体实现起来相对简单。下面是碰到的一些问题。

topViewController 不是在 keyWindow 上

解决办法是获取 Appdelegate 中的 window 的 topViewController

AlertView 和 AlertController

解决办法是 hook dismissViewControllerAnimated 方法并且将相关的类名加入到特殊 Controller 列表中,在处理这些特殊 Controller 时,将获取前一个控制器的方向

具体实现代码可前往 Git 上查看

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容

  • 目录 一、最让人纠结的三种枚举 二、两种屏幕旋转的触发方式 三、屏幕旋转控制的优先级 四、开启屏幕旋转的全局权限 ...
    来闹的阅读 2,862评论 0 4
  • 第一步 首先保证工程支持横竖屏 不多说看图 保证圈红的地方 打对勾 58F678EC-EABC-4320-9FCB...
    ylgwhyh阅读 1,788评论 0 1
  • iOS 中横竖屏切换的功能,在开发iOS app中总能遇到。以前看过几次,感觉简单,但是没有敲过代码实现,最近又碰...
    零度_不结冰阅读 2,179评论 0 0
  • 概述 写代码就是在不断填坑的过程中慢慢成长,程序员哪有不遇坑的呢? 这篇文章来谈谈iOS中横竖屏切换的一些坑,横竖...
    jumpingfrog0阅读 11,317评论 6 21
  • IOS 设备横竖屏情况 一般情形 所有界面都支持横竖屏切换如果App的所有切面都要支持横竖屏的切换,那只需要勾选【...
    leonardni阅读 1,809评论 0 0