简介: 随着移动互联网设备和技术的发展,各类移动设备屏幕尺寸层出不穷,折叠屏、分屏、悬浮窗等等,面对愈来愈多样的屏幕,若是为每种尺寸单独进行适配,不只费时费力,还会增长端侧代码的开发与维护压力。如何让一套代码适配全部尺寸变化,加强App的通用能力?阿里巴巴文娱技术 氚雨 将分享优酷APP在iOS响应式布局技术上的实践和落地。数据结构
响应式是基于同一套代码,开发一个APP可以兼容多尺寸、多终端设备的显示,可以动态调整页面的布局以及容器的布局,充分利用当前屏幕的尺寸,为用户提供更好的浏览体验,提高APP开发效率和迭代效率。架构
当下,iOS端的主要尺寸类型有五种:iPhone、iPad竖屏、iPad横屏、iPad浮窗、iPad分屏。一般,App是按iPhone尺寸开发的,须要适配剩余的四种iPad尺寸。app
iPad横、竖屏比较常见,旋转设备便可,比较特殊的是浮窗和分屏模式。自苹果iPad iOS 9开始,用户在打开一个应用时,从最底部上滑打开Dock,便可拖拽另外一个App进入浮窗模式:框架
在支持分屏的iPad上拖拽到更边缘的地方便可开启分屏模式:布局
其中浮窗模式全部升级iOS 9的设备都支持,分屏模式只有最新版的硬件设备iPad mini 四、iPad Air 2及iPad Pro支持:性能
响应式布局的核心是设计统一的适配规则,并在屏幕尺寸发生变化时按布局规则从新布局,以适配不一样屏幕尺寸,而大多数App在开发时通常只有适配iPhone的版本,在经过响应式适配更多机型时主要要解决三个方面的问题,即如何获取、更新响应式状态以进行对应的适配,如何计算在不一样屏幕宽度下App内容的宽度、列数等布局参数,如何进行响应式下的数据处理以解决较难适配的组件、减小页面留白等,基于此咱们开发了响应式布局SDK,负责统一管理响应式状态、处理布局逻辑、裁剪映射数据等。ui
App除了配置为universal版以外,要支持浮窗或分屏模式还须要进行一些配置:阿里云
(1)须要提供LaunchScreen.storyboard做为启动图,因为App支持的运行尺寸太多,再也不适合用图片做为启动图。spa
(2)须要在info.plist中配置支持全部屏幕方向:设计
(3)注意不能勾选Requires full screen配置项或配置UIRequiresFullScreen为YES,如此会声明App要求全屏运行,天然表示不支持浮窗或分屏:
(4)支持分屏要求App的主Window须要使用系统UIWindow,不能继承,而且要经过init方法或initWithFrame:[UIScreen mainScreen].bounds方式初始化。
经过以上步骤开启浮窗、分屏能力后,在App内就没法再经过相关代码控制设备方向,以往经过以下代码可控制ViewController为竖屏,而支持分屏后以下方法系统再也不调用,默认全部ViewController支持全部屏幕方向:
以下强制设置屏幕方向的黑方法也已失效:
这种设计的主要缘由是,当一个App支持分屏后,就再也不单独占用整个屏幕,当另外一个App同时运行时,同一块屏幕不可能出现一个横屏、另外一个竖屏。此类问题没有完美的解决方案,为了保证用户体验,支持分屏的App必须全部页面适配全部屏幕方向,这也体现了苹果对用户体验的极致追求,参见DeveloperForums中开发人员的讨论:
https://developer.apple.com/forums/thread/19578
响应式状态管理
响应式状态提供了当前是否开启响应式、响应式布局尺寸类型、当前布局window尺寸等相关状态量,响应式SDK会在屏幕尺寸变化后更新响应式状态,并经过系统通知和自定义通知机制,通知相关业务方。
// 响应式开启关闭状态 typedefNS_ENUM(NSInteger, YKRLLayoutStyle) { YKRLLayoutStyleNormal =0, // 响应式状态关闭 YKRLLayoutStyleResponsive =1, // 响应式状态开启}; // 响应式屏幕尺寸类型,页面可依据此类型区分是否分屏等 typedefNS_ENUM(NSInteger, YKRLLayoutSizeType) { YKRLLayoutSizeTypeS =0, // eg. phone pad浮窗 YKRLLayoutSizeTypeL =1, // pad YKRLLayoutSizeTypeXL =2, // 预留 }; // 响应式屏幕状态类型(一共有十种类型) typedefNS_OPTIONS(NSUInteger, YKRLLayoutScreenType) { YKRLLayoutScreenTypeUnknown = (1<<0), //未知 YKRLLayoutScreenTypePortrait = (1<<1), //竖屏全屏 YKRLLayoutScreenTypeLandscapeLeft = (1<<2), //横屏全屏左 … … };
响应式SDK声明了YKRLLayoutStyle、YKRLLayoutSizeType、YKRLLayoutScreenType三种枚举状态标记当前的响应式状态,分别表示响应式开启关闭状态,当前尺寸类型及具体屏幕类型,通常业务方只须要获取是不是响应式设备状态,对于在不一样宽度下页面布局不一致的业务方能够经过尺寸类型状态进行区分适配,而对于须要具体知道当前屏幕状态的业务方能够经过屏幕类型获取,屏幕类型只包含当前iOS设备已支持的屏幕状态,随着设备类型的丰富,如出现折叠屏等,屏幕类型会做相应扩展。每当设备旋转或用户开启分屏时,响应式SDK都会在系统回调中更新当前响应式状态,并通知业务方响应式状态的改变。
响应式布局规则
优酷响应式布局规则主要包含列数适配规则、宽度适配规则等,好比多列均分组件的列数在不一样屏幕宽度下是可变的,响应式SDK会根据当前的响应式状态输出合适的布局列数等,对于每个布局规则,响应式SDK中都有相应的布局适配逻辑,响应式布局规则知足优酷App总体UI规范,业务方直接指定本身所须要的规则便可,除少数特殊规则以外,大部分布局规则都用于组件列数和组件宽度布局,此类响应式布局规则中会指定一个标准宽度,并根据组件原始布局列数和标准宽度计算出组件标准宽度,进而根据当前屏幕宽度计算出适配后的组件列数,可用以下公式表达:
响应式适配列数(标准屏幕宽度下组件列数) = (当前屏幕宽度÷(标准屏幕宽度÷标准屏幕宽度下组件列数×scale))
其中,scale为组件放大参数,标准屏幕宽度下组件原宽度投放到iPad上会太小,能够经过scale参数进行适当放大。
对于组件宽度适配,响应式规则会先计算标准屏幕宽度下的组件列数并进行列数适配,再经过适配后的列数计算适配宽度:
响应式适配宽度(标准屏幕宽度下组件宽度) = (当前屏幕宽度 - 边距间距)÷响应式适配列数(标准屏幕宽度÷标准屏幕宽度下组件宽度)
在以上公式中调整标准屏幕宽度及组件放大scale便可获得适配效果较好的通用布局规则,通过设计同窗在各类设备尺寸下的调整总结,当前优酷中使用的标准屏幕宽度为440dp,scale为1.2倍,适配效果最佳。组件适配逻辑已在响应式SDK布局规则中统一实现,业务方直接调用便可,也方便设计同窗对整个App的组件适配进行统一调整。
响应式SDK中YKRLCompLayoutManager类封装了相关布局逻辑,业务方也可经过YKRLCompLayoutAdapterProtocol协议二次处理,以定制响应式布局逻辑,在App统一架构中直接调用YKRLCompLayoutManager的相关接口便可获取按照响应式规则计算后的布局参数,如列数、宽度等,当监听响应式状态发生变化时从新布局便可完成响应式布局。
响应式数据处理
响应式数据处理包括数据映射、数据过滤、数据合并、数据补齐,数据处理逻辑两端一致,详细介绍能够参见:一个APP如何适配多个Android终端?,下面简单介绍一下iOS响应式数据映射的实现。
有些组件没法经过规则适配不一样的屏幕尺寸,好比在手机上占整个屏幕宽度的组件(下图左侧带视频播放预定组件),若是采用等比放大的适配规则,在iPad端会显得过大,此类组件能够映射成相对简单的组件,以适配不一样的屏幕尺寸。
优酷采用了统一抽象的数据结构,在组件映射方面比较容易实现,只需修改对应的组件标志便可。得益于统一架构的广泛推广和使用,咱们在统一架构内添加了组件映射能力,方便各业务方调用,响应式SDK中提供了数据裁剪映射规则,业务方能够查询、增长相应的裁剪映射规则。对于未接入统一架构的业务方则须要业务方实现相关数据处理。
优酷响应式业务流程两端一致,响应式布局须要进行数据处理、响应式状态管理、触发布局等工做,优酷响应式SDK会在接口返回后处理相关数据,为统一架构提供相应布局接口,监控屏幕尺寸变化并触发布局等。
iOS开发中常常采用绝对布局,而实现响应式的主要工做是将“绝对布局”修改成“相对布局”,接入工做较安卓更为繁琐。
iOS响应式能够按Window->ViewController->容器->组件的层级完成接入。
Window在配置支持分屏后会由系统自动布局,在RootViewController树中的子ViewController也会随Window自动布局,而特殊ViewController,如多tab页面的子ViewController等,未加入RootViewController树,须要手动修改成相对布局,页面可经过Autoresizing或监听响应式状态实现相对布局。
接入统一架构的页面容器由统一架构提供,统一架构容器的布局列数管理、布局宽度管理等都已接入响应式SDK,为业务方接入减小了大量工做,业务方只需指定自身所采用的布局规则便可,ViewController和容器实现相对布局后,每当屏幕尺寸变化时响应式SDK会通知容器从新布局,变换组件列数或宽度等,组件卡片只须要按容器提供的尺寸进行布局便可。
组件卡片内通常使用Frame绝对布局,须要修改成相对布局,简单的布局逻辑可使用Autoresizing实现,方便快捷,复杂的布局可使用AutoLayout或Masonry等自动布局框架(性能较差)实现,也能够在layoutSubviews方法中从新计算布局,业务方能够选择合适的方式实现自动布局,以减小接入成本。
对于未接入统一架构的页面则须要在本页面布局逻辑中手动接入响应式SDK相关布局接口。
落地过程当中发现许多组件卡片布局时依赖了屏幕宽度,不符合响应式开发规范,致使适配响应式时工做量较大。每一层View只应依赖父层View布局,各层View实现相对布局后,每当屏幕尺寸改变时各层View会自动适配,同时容器的组件列数和尺寸会按响应式规则进行适配,一套代码便可适配全部屏幕尺寸,实现响应式布局。
目前优酷全端已具有响应式布局的能力,八月份已上线universal版本,一套代码支持iPhone、iPad竖屏、iPad横屏、浮窗、各类比例分屏,为用户提供了更好更丰富的用户体验。
响应式能力是多端投放能力的第一步,优酷实现响应式布局后对开发、设计和产品都提出了更高的要求,同时鉴于iPad低端设备占比较高,业务开发过程当中不只要考虑通投能力,更要求App始终保持更高的性能和稳定性,这是咱们持续在努力的。
苹果2020年末将推出基于ARM架构的MacBook,也有媒体曝光,苹果正在申请折叠屏相关的专利,相信将来苹果设备的尺寸会愈来愈丰富,App适配提效是绕不开的话题,而优酷响应式的开发极大扩展了iPhone版App的适用场景,是解决多种设备支持的更好途径,为适应将来更复杂的设备场景打下坚实基础。
原文连接本文为阿里云原创内容,未经容许不得转载。