TB前卫网

TB前卫网店铺大全为您精选最好的精品店铺导航,欢迎您。收藏本站

[iOS]终极横竖屏切换解决方案

栏目:科技数码   发布时间:2017/07/25   来源:Cocoa开发者社区   编辑:cocoachinabbs

解决方案

大家的项目都是只支撑竖屏的吧?大多数朋友(这其中固然也包含博主),都没有做过横屏开发,这次项目恰好有这个需求,因而把横竖屏相关的心得写成一遍文章供诸位参考。


01.综述


大多数公司的项目都只支撑竖屏,只有一两个界面需要同时支撑横屏,就像视频 APP 同样,只有视频播放的时候需要横屏,其他时候都只允许竖屏。给出的 demo 中处理两种需要横屏的情景:


  • 第一种是录制视频时横屏
  • 第二种是播放视频时横屏


具体使用演示请前往优酷视频查看:BLLandscape Demo。

02.录制视频横屏

一般可能只需要播放视频时横屏,录制横屏一般用不到,然而如果有朋友需要做横屏视频录制,这时候候就需要录制横屏处理,就像下面这样的。


这个思路是这样的


这个思路是这样的:


  • 横屏的时候,首先把要横屏的 view 从本来的 superView 中移除了,添加到当前的 keyWindow 上,然后做 frame 动画,将窗口的高设为 view 的宽,窗口的宽设置为 view 的高,然后将 view 的旋转 90°,履行动画,就可以得到当前的效果。
  • 竖屏的时候,是一个相反的进程,先在窗口上做完动画,再将 view 插入到横屏以前的 superView 中的对应位置上。

2.1.横屏切换

我把这些实现都抽成一个 UIView 的分类,看一下实现:







2.2.竖屏切换

竖屏和横屏就是一个相反的进程,这里不贴代码也不做解释了。不懂的去看源码就了解了。

2.3.注意点
2.3.1.分类中实现 weak

源码没啥难度,然而有一个细节需要注意,我们要在分类中以 weak 的内存管理方法去援用动画以前的 superView,以便我们回来做竖屏动画完成之后将当前 view 添加到动画以前的 superView 上。然而在分类中添加属性的内存管理方法中没有 weak 属性,然而有一个 OBJC_ASSOCIATION_ASSIGN,它相似我们经常使用的 assign,assign 方法的特色就是在对象释放之后,不会主动将利用的对象置为 nil,这样会有走访僵尸对象致使利用崩溃的风险。
为知道决这个问题,我们可以创立一个替身对象,我们可以在分类中以 OBJC_ASSOCIATION_RETAIN_NONATOMIC 的方法来强援用替身对象,然后在替身对象中以 weak 的方法去援用我们真实需要储存的对象。这样就可以解决这个可能致使崩溃的问题了。

2.3.2.布局

因为我们做的是 frame 动画,所以以后在这个 view 上再添加子控件的时候必需使用 frame 布局,Autolayout 布局在当前的 view 上将不会被更新,致使 UI 错乱。


播放视频横屏

03.播放视频横屏

大多数场景都是播放视频的时候横屏,譬如下面这样的:


如果你在网上搜 iOS 横竖屏切换 能搜到的也就是播放视频的时候的横屏了,而这些文章仿佛都是抄的某一篇文章,大家说的都同样。尽管大家抄来抄去,仿佛他们在文章中写的都能解决问题,但实际上他们的文章是不能解决实际问题的。

3.1.播放视频横屏

我们来看一下节制屏幕旋转的两个策略:






可以看到可以节制屏幕方向的策略是定义在 UIViewController 里的,第一个 -shouldAutorotate 策略,系统会讯问当前节制器是不是支撑旋转,第二个策略 -supportedInterfaceOrientations 告知系统当前节制器支撑那几个方向的旋转。
真实项目中,我们的 UI 架构多是这样的:


我们的项目中从窗口开始


我们的项目中从窗口开始,顺次是一个根节制器,然后再是 UITabbarController 然后再是 UINavigationController,最后才到我们的 UIViewController,我们是某些界面需要横屏,所以必需要把系统的讯问细化到每一个节制
器的策略才行。


我们看下一个横竖屏事件的传递过


结合上图,我们看下一个横竖屏事件的传递进程:


  • 先是陀螺仪捕获到一个横屏事件
  • 接下来系统会找到当前用户操作的那个 APP
  • APP 会找到当前的窗口 window
  • 窗口 window 会找到根节制器,这个时候事件终究传到我们开发者手里了
  • 至于我们自定义的根节制器,它需要把这个事件传递到 UITabbarController
  • 至于 UITabbarController,需要把事件传递到 UINavigationController
  • 至于 UINavigationController,需要把事件传递到我们自己的节制器
  • 最后在我们自己的节制器中抉择某个界面是不是需要横屏


等等,你我的项目是一个已可能有上千个节制器的大工程了,如果依照这个逻辑走下去,我们要在每一个节制器写这个两个策略,不敢想象。
此时我们第一要思考的就是借助分类来实现,既简单又俊雅,而且保护起来集中干净,何乐而不为?








3.2.注意点
3.2.1. JPWarpViewController

当前 demo 中使用了 JPNavigationController,由于 JPNavigationController 结构的特殊性,所以这里加了一个







如果你项目中有为每一个界面定制导航条的需求,你或者许可之前往我的 GitHub 查看。

3.2.2.AVFullScreenViewController


3.2.3.实现有视频的网页需要横屏

其实不是所有的网页都需要横屏,然而如果这个网页有视频,常常需要横屏,那我们怎样了解某个页面是不是需要横屏,是不是有视频呢?
一种方式是和 h5 商定一个事件,如果有视频就告知原生 APP 做一个标记,将 bl_shouldAutoLandscape 置为 YES。
然而我这里提供一种更为简便俊雅的方式,我们的 UIWebView 是可以通过 -stringByEvaluatingJavaScriptFromString: 策略和我们交互的,所以我们可以尝试下面的策略:








当 WebView 加载完之后,我们去查找当前的 h5 页面中有没有 Video 标签,如果有,那我们就能够拿到结果,做对应的横屏处理。

3.2.4.大坑来了

原本我们的这个 UITableViewController 是不支撑横竖屏的,就像这样,注意,这个时候那个 UISwitch 按钮是关闭的。


我们把这个开关打开


接下来,我们把这个开关打开,这个开关对应的代码是这样:






就是打开后会为此外一个窗口添加一个根节制器,而这个根节制器的代码是这样的:





这样之后,我们察看一下节制器的表现:


看起来我们的主界面确实仍然不支


看起来我们的主界面确切依然不支撑横竖屏,这是没有问题的,然而好像我们的状况栏被蓝色的这个窗口劫持了,它们俩莲开并蒂,一块儿干了这么一个横竖屏的勾当。
我们想象一下,现在这个蓝色的窗口在最前面,我们能麻利的察看到时这个蓝色的窗口劫持了状况栏。那如果这个蓝色的窗口在我们的主窗口后面呢,那我们根本就不会发觉到这个细节,我们能看到的就是下面这样:


第一次碰到这个


第一次碰到这个 bug,我的内心是崩溃的。
我们一块儿来分析一下这个问题是怎样酿成的。再来看一下这个横竖屏系统讯问路径图,当我们有多个窗口之时,每一个窗口都是同等的,那个蓝色的窗口也收到了系统的讯问。


  • 还记得以前两个系统讯问的策略是 UIViewController 的策略,此时如果窗口并无 rootViewController 的话,那系统问也白问,所以蓝色窗口其实不会劫持状况栏和横屏事件。
  • 如果此时蓝色窗口有 rootViewController 的话,那末该节制的返回值就会抉择装备的方向。也就造成为了这个 bug。


地址在这里

04.最后

最后 GitHub 地址在这里 BLLandscape。


我的文章聚拢下面这个链接是我所有文章的一个聚拢目录。这些文章凡是触及实现的,每一篇文章中都有 Github 地址,Github 上都有源码。如果某篇文章恰好在你的实际开发中帮到你,又或提供一种不同的实现思路,让你觉得有用,那就看看这句话 “坚持每一天点赞的人,99%都是帅哥美女,不再用独身了”。



我的文章聚拢索引
如果你有问题,除在文章最后留言,还可以在微博 @盼盼_HKbuy上给我留言,以及走访我的 Github。




SELECTION一周精选


7 月份五大使人惊叹的 iOS 库谈谈 MVX 中的 Model
2017 开发者生态讲演:Java 最火,Go 最有前程
IEEE发布2017年编程语言排行榜:Python高居首位,PHP第8,猜猜Swift和OC排第几
最新iOS发布App Store详细图文教程
iOS 如何优化项目





【公众号】:Cocoa开发者社区
【微信号】:cocoachinabbs
【微宣言】:CocoaChina苹果开发中文社区官方微信,提供教程资源、app推广营销、招聘、外包及培训信息、各类沙龙交流活动以及更多开发者服务。

下一篇:应用程序遇到性能问题了怎么办?
*版权声明及防欺诈提醒