iOS 播放视图的横竖屏切换实现

横竖屏切换,只要是在视频播放类app中就一定会遇到的问题。之前一直以为很简单,但当自己真的遇到这个问题的时候,才发现然来是之前的我很简单。

这里我将我在实现过程中遇到的问题和需要注意的地方做了一个总结,并写了一个小demo,并分享出来。demo最终运行效果图如下:


效果图.gif

工程配置

在开始代码之前必须先让我们的工程支持横竖屏,这就需要在xcode设置中General里面进行勾选配置:

工程配置.jpeg

当然支持横竖屏在工程中是默认勾选。为了方便控制statusBar(状态栏),我在info.plist文件中添加View controller-based status bar appearance=NO字段,让statusBar的状态由application控制,而不是控制器。配置完工程之后,就是该如何具体实现了。但在开始代码之前,先应该清楚自己要用什么样的方法去实现这个效果呢?

思路

第一次看到这个问题,我的想法是:对视频播放的view做一个旋转放大的动画,然后改变statusBar的方向就行了。结果发现:第一步很容易实现,到第二步就尴尬了。

@property(readwrite, nonatomic) UIInterfaceOrientation statusBarOrientation NS_DEPRECATED_IOS(2_0, 9_0, "Explicit setting of the status bar orientation is more limited in iOS 6.0 and later") __TVOS_PROHIBITED;
- (void)setStatusBarOrientation:(UIInterfaceOrientation)interfaceOrientation animated:(BOOL)animated NS_DEPRECATED_IOS(2_0, 9_0, "Explicit setting of the status bar orientation is more limited in iOS 6.0 and later") __TVOS_PROHIBITED;

利用application控制statusBar方向的方法都被禁用了,即使硬着头皮写了,发现还是不行。既然这样不行,那我先让当前控制器切换成横屏,然后再对视频播放的View做动画。如果这样做,我首先面对的问题就是:如何主动触发屏幕旋转?查阅文档后发现,只有UIDevice这个类与屏幕方向有关。

@property(nonatomic,readonly) UIDeviceOrientation orientation __TVOS_PROHIBITED;

如上所示,我还没开心的太久,就发现UIDevice这个类能设置屏幕方向的只有orientation这个属性,但这个属性是只读的。这就意味着如果我想主动触发屏幕旋转就必须使用系统私有的方法,所以让当前控制器主动切换屏幕方向也行不通。

在经历了两次失败之后,我才知道:在当前控制器里改变statusBar的方向是行不通的。所以要想做到statusBar的切换就必须切换控制器,具体操作如下:

  1. 当用户点击切换屏幕按钮后,Modal出一个新的控制器
  2. Modal控制器只能试横屏向左或向右
  3. 对Modal控制器做一个旋转动画,使其看起来像一个Modal过渡动画
  4. 切换到竖屏时,只需要Dismiss掉Modal控制器
  5. 对播放视图做一个旋转动画,同样使其看起来像一个Dismiss过渡动画

PS:这里为什么要用Modal动画而不用Push,有兴趣的可以在demo中测试下

代码实现

当前控制器只支持竖屏,Modal控制器只支持横屏,所以需要重写UIVIewController的UIViewControllerRotation分类方法,具体代码如下:

- (BOOL)shouldAutorotate{
    return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return UIInterfaceOrientationPortrait;
}

说明:

  1. 在Modal控制器中只需将UIInterfaceOrientationMaskPortrait换成对应的UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight就行了
  2. 因为屏幕方向是由当前窗口下的根控制器控制,所以在根控制器中也需要重写上面三个方法,这样每个子控制器才能控制自己的方向。详情参考iOS Rotation

确定了控制器方向之后,在切换全屏时只用Modal出一个新控制就行了,具体代码如下:

SecondViewController *secondVC = [[SecondViewController alloc] init];
secondVC.delegate = self;
secondVC.orientation = orientation;
[self presentViewController:secondVC animated:NO completion:nil];

说明:

  1. 传orientation参数,是为了通知Modal控制器显示的方向是横屏向左还是向右
  2. Modal时不能带动画,这里会用旋转动画模拟过渡动画

实现了这些,再添加上旋转动画(动画代码具体实现可以参考demo),就可以实现点击按钮切换全屏效果。

完善

实现了点击按钮切换全屏,那用户转动手机方向就自动切换到全屏,这个如何实现呢?要实现这个功能,首先我们需要知道用户转动手机这个事件。系统利用UIDeviceOrientationDidChangeNotification通知将事件传出,监听通知代码如下:

 [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];

监听到事件,就是具体的逻辑处理,代码如下:

if([UIDevice currentDevice].orientation == UIDeviceOrientationPortrait) {
        [[UIApplication sharedApplication] setStatusBarHidden:NO];
        [self orientationChange:UIInterfaceOrientationPortrait];
    } else if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft) {
        [[UIApplication sharedApplication] setStatusBarHidden:NO];
        [self orientationChange:UIInterfaceOrientationLandscapeLeft];
    } else if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight) {
        [[UIApplication sharedApplication] setStatusBarHidden:NO];
        [self orientationChange:UIInterfaceOrientationLandscapeRight];
    }

说明:

  1. orientationChange:方法实质就是根据屏幕方向Dismiss或Modal一个控制器,具体代码实现,可参考demo

至此,整个效果就已完成。

结尾

希望这篇文章能帮助大家了解到iOS屏幕旋转机制与如何控制,如果你觉得这篇文章对你有帮助,希望能赞一下或是上GItHub start一下,毕竟你们的认同才是我继续分享下去的动力。

最后奉上demo地址

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

推荐阅读更多精彩内容

  • 前言的前言 唐巧前辈在微信公众号「iOSDevTips」以及其博客上推送了我的文章后,我的 Github 各项指标...
    VincentHK阅读 5,362评论 3 44
  • 所有的视频类App都会面临一个播放器横竖屏切换的问题,之前一直使用KVO强制修改设备方向达到竖屏转为横屏。 目前看...
    光无影阅读 8,300评论 11 34
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,102评论 4 62
  • 说起读书,真是一个经典久不衰落的话题。近两千年的中华历史长河上,小到大街小巷,大到繁华圣地,人们总是在讨论...
    linux_writer阅读 300评论 0 0
  • 斯金纳的“不确定性巩固”理论在后来的几十年内不断受到反对,但所有反对者重复实验都能得到类似的“迷信”行为。
    京鹿子娘道成寺阅读 201评论 0 0