保质期网

 > 最新资讯 / 正文

爱奇艺短视频怎么全屏,热门短视频爱奇艺

admin 2021-11-22 05:42:44 最新资讯 评论
  

  对于一款具备视频播放功能的app产品来说,视频全屏是一个基本且重要的要求。虽然这个需求看起来很简单,但是我们已经在实现前后迭代了三套技术解决方案。本文将介绍这三种实施方案的优缺点和陷阱,以及在实施过程中积累的经验。   

  

  关键要求:   

  

  *在屏幕旋转的动画中,需要将界面布局保持在播放器之外(例如“First View”等几行字的布局不应该改变)。   

  

  *全屏切换到小屏,小屏需要回到原来的位置。   

  

     

  

  对于这三种实现方案,我分别写了一个演示。这三个方案在演示的三个选项卡中。   

  

  原方案:方案一。   

  

  从小屏移动到全屏时,将播放器所在的视图放置在窗口上,以变换的形式制作旋转动画,使视图完全覆盖窗口。   

  

  从全屏返回到小屏时,以变换的形式旋转动画,最后将玩家所在的视图返回到原来的parentView。   

  

  核心代码示例:   

  

     

  

  这个方法在实现上相对简单,因为它只旋转玩家所在的视图。   

  

  控制器和设备的方向总是纵向的。但最大的问题是全屏状态。   

  

  条形的方向仍然是垂直的。虽然之前通过全屏隐藏statusBar的方式掩盖了这个问题,但也导致用户无法在全屏视频中看到时间和网络情况,体验有待提升。   

  

     

  

  方案二假设   

  

  为了解决状态栏无法切换为横向的问题,我们决定更换全屏幕视频的实现方式。   

  

  业界最流行的屏幕转移方式应该是通过私有接口设置UIDevice的orientation属性。但是直接设置这个属性实现的转屏动画效果有些欠缺。例如,黑色会在旋转过程中漏出。   

  

  由于setStatusBarOrientation等方法已经被标记为折旧,使用它可能会带来风险,所以我们暂时没有考虑这个方法。   

  

  一种合理的技术方案是:   

  

  在只支持纵向的视图控制器上,显示的是只支持横向的视图控制器。通过重写视图控制器之间的过渡动画,可以高度定制全屏动画,并且当视频全屏时,可以水平显示状态栏。   

  

  该方案不使用任何私有接口或黑客手段,完全符合苹果的要求。理想情况下,它应该是一个稳定可靠的方案。   

  

  因此,我们选择了当前视图控制器作为第二个选项。   

  

  核心设计是:   

  

  添加ViewController的一个子类,在演示中是FullscreenViewController,并覆盖这个类的supportedInterfaceOrientations返回uiinterfaceorientmasclandscape。   

  

  当显示全屏时,系统会自动将状态栏转向横向。   

  

  同时,定制FullscreenViewController的过渡动画,形成符合产品要求的动画效果。   

  

  方案二坑点解。   

  

  在实现第二个方案的过程中,我们遇到了很多问题。   

  

  生意场上的坑。   

  

  *兼容viewWillDisppear等生命周期方法   

  

  默认情况下呈现一个视图控制器会导致presentingViewController的视图从视图层次结构中被移除,调用presentingViewController的viewing方法,这将极大地影响原有的业务逻辑。   

  

  经过调查发现,使用UIMap Representation OverFullsCreen来呈现不会影响到presentingViewController的生命周期。   

  

  *对iOS7的兼容   

  

  uiodalpresentationoverullscreen仅支持iOS8以上的系统。对于iOS7,我们使用UIModalPresentationCustom的当前模式。但是,在iOS7和iOS8中,视图级别。   

结构有所不同,导致iOS7下需要进行特殊兼容:

  

在iOS8及以上,present一个viewController时,view的层次结构是

  

  

在iOS7中,present一个viewController时,view的层次结构是

  

  

所以在iOS7中,需要自行将presentedViewController.view应用transform变形,让它旋转90度达到横屏的效果。

  

在demo中,进入全屏的动画对iOS7和iOS8及以上系统做了分别处理:

  

iOS7:进入全屏的动画开始前,设置presentedViewController.view.transform =

  

CGAffineTransformIdentity,为的是让presentedViewController.view覆盖在播放器view的位置上,形成动画起始的布局;在全屏动画的过程中,设置presentedViewController.view应用transform变形,让它旋转90度达到横屏的效果;

  

iOS8及以上:进去全屏的动画开始前,由于presentedViewController.view已经被系统旋转了90度,所以我们也让presentedViewController.view旋转90度,才能覆盖在播放器view的位置上;在全屏动画的过程中,设置presentedViewController.view.transform

  

CGAffineTransformIdentity,由于它的父视图已经是横向状态,所以此时presentedViewController.view看起来也称为了横屏状态。

  

具体代码可以参考demo中的EnterFullscreenTransition和ExitFullscreenTransition两个类。

  

* 部分控件依靠window尺寸布局,导致全屏动画过程中布局错乱

  

在iOS8及以上系统中,present的动画过程中,iOS对presentingViewController的view的frame经过了两次变化:

  

第一次变化:由于window的bounds从竖直(height > width)的状态变化为了横向(width >

  

height)的状态,由于autoresizing的作用,presentingViewController.view的frame也变成了横向状态

  

第二次变化:系统给presentingViewController.view增加了transform使其旋转了90度,让presentingViewController.view看起来还是竖直方向的

  

如果一个presentingViewController.view的一个子视图通过读取window的宽高来布局,那么在第一次变化的时候,window的宽高已经对调,导致第二次变化时这个子视图的布局错乱。

  

demo中,方案二内的红色小字展示了这个bug。

  

  

* Window横竖屏的切换导致tableView被reloadData

  

上一个问题中讲到,在present的过程中,iOS对presentingViewController的view的frame经过了两次变化,这很可能会导致presentingViewController中的tableView被触发reloadData。

  

原本,为了让一个视频在退出全屏时回到原来的位置上,我们只需要记录movieView的superView以及movieView小屏状态下的frame,退出全屏时将movieView重新添加到superView上即可(如demo中的实现方式)。但是如果这个superView是一个tableViewCell的话,reloadData会导致cell的重用。退出全屏时将movieView添加到superView上,反而会导致视频视图回到了错误的位置。在这种情况下,我们只能改为记录movieView所在cell的index来弥补这个问题。

  

另外,由于我们的app对tableView做了高度缓存等优化,在一些极端情况下,这两次出乎意料的reloadData导致了一些业务上的bug,比如存入了错误的高度缓存。

  

# 系统级的坑点

  

如果说业务上的坑点都能通过修改代码逻辑来依次解决,但系统级的坑点却很难有有效的解决方案。

  

* 屏幕渲染bug导致半边黑屏问题(iOS10)

  

在开发过程中发现,这种全屏方式会偶现手机半边黑屏的问题。在主线程忙碌时这个问题有较大的复现概率。

  

  

比如在这张图中,系统statusBar的宽度明显是横屏时的宽度,但是在渲染时整个界面都被旋转了90度,造成下方出现了半边黑屏。

  

但是在这种情形下,如果读取UIWindow,UIScreen以及各个层次的view的frame,得到的数值都符合预期,唯独屏幕上渲染出来的结果是bug的。

  

  

写了几个demo表明,这个即便没有转场动画,只要present一个只支持横屏方向的ViewController,半边黑屏的问题就有概率复现。

  

尝试了在全屏动画完成后再设置UIDevice的orientation,设置StatusBarOrientation等方法,但均没能解决这个问题。

  

* UIScreen长宽互换bug(iOS10)

  

当app在后台时,触发了present操作,再返回前台,会导致读取UIScreen时长宽被互换了,但此时UIWindow的长宽却是符合预期的。

  

如果其他业务中,有界面是通过读取UIScreen的长宽来布局的话,这时就会出现布局异常的bug,比如某一段时间的详情页:

  

  

  

对于这个问题,我们采用了两个walkaround的方案:

  

(1)当app在后台时,禁止触发全屏相关的代码; (2)各业务不依赖UIScreen布局,比较好的做法是仅依赖superView进行布局;

  

方案二放弃

  

屏幕渲染bug导致半边黑屏问题一直得不到解决,并且在腾讯视频、爱奇艺等app上也发现了类似的bug。

  

  

  

针对这个问题,我们尝试了苹果的Apple Developer Technical

  

Support,通过这个渠道可以接触到苹果的工程师,也许能给我们提供一些绕过这个bug的方法或者其他意见。在回信中,苹果承认这是他们的一个bug,但暂时没有给出解决方案。

  

  

无奈之下,我们只能放弃了方案二,开始寻求其他的方案。

  

方案三尝试

  

方案三尝试了一个看起来不太合理的方案:

  

> 在方案一的基础上,调用UIApplication的setStatusBarOrientation:animated:方法来改变statusBar的方向

  

> 同时重写当前的ViewController的shouldAutorotate方法,返回NO

  

官方文档对setStatusBarOrientation:animated:方法的描述是这样的:

  

> Sets the app's status bar to the specified orientation, optionally animating

  

> the transition. Calling this method changes the value of the

  

> statusBarOrientation property and rotates the status bar, animating the

  

> transition if animated is YES . If your app has rotatable window content,

  

> however, you should not arbitrarily set status-bar orientation using this

  

> method. The status-bar orientation set by this method does not change if the

  

> device changes orientation.

  

这个方法已经被depreciate了,并且文档中也透露出不希望开发者调用的意思,然而神奇的是,使用这个方法并配合shouldAutorotate返回NO,竟然能旋转statusBar,并且让动画效果符合产品需求。

  

在supportedInterfaceOrientations的文档中,有这样的说明:

  

> When the user changes the device orientation, the system calls this method

  

> on the root view controller or the topmost presented view controller that

  

> fills the window. If the view controller supports the new orientation, the

  

> window and view controller are rotated to the new orientation. This method

  

> is only called if the view controller's shouldAutorotate method returns

  

> true.

  

也就是说,当shouldAutorotate为NO的时候,supportedInterfaceOrientations方法将不再被调用。由于无法窥探UIKit的内部实现,我们只能猜测,当shouldAutorotate为NO的时候,界面的方向将不受supportedInterfaceOrientations控制,转而被setStatusBarOrientation:animated:方法控制。

  

虽然方案三看起来有些出乎意料的简单,但使用这个方案,我们比较顺利的完成了视频全屏的需求。

  

参考资料

  

supportedInterfaceOrientations

  

setStatusBarOrientation:animated:

  

shouldAutorotate

  

Tags:

猜你喜欢

留言与评论(共有 0 条评论)
   
验证码:
搜索
网站分类
标签列表