本文介绍一种通用的2D画面布局适配方案,在移动设备多种设备分辨率情况下依然有非常好的设计效果。该方案可以使得UE可以在固定分辨率上进行UI设计,在几乎不影响基本布局的情况下,出色的完成UI自动布局。作者使用的是cocosui,本文也会提出修改cocosui 的方法。
一、Auto Layout
Auto Layout是IOS提出的一种布局、排版的解决方案,通过Auto Layout System,我们可以创建出动态和灵活的UI,轻松应对屏幕尺寸的变化,横竖屏切换,不同OS版本上布局的兼容等情况。本文参考了Auto Layout的设计思路,详情请戳这里。
二、旧的方案
1、预备知识
现在市面上的主流分辨率如下
Android
[840, 480] = 15:9 HTC
[1280, 720] = 16:9
[854, 480] = 16.05:9 SonyErisson LT18i
[960, 540] = 16:9
[1920, 1080] = 16:9
[1184, 720] = 14.8:9
[1280, 800] = 16:10
[1776, 1080] = 14.8:9 LG(L36h) #1920*1080,坑爹的任务栏占了一部分空间
[976, 600] = 16:9.836
[888, 540 = 14.8:9]
[800, 600] = 4:3
IOS
[1920, 1080] = 16:9
[1334, 750] = 16:8.9955
[1136, 640] = 16:9
[960, 640] = 3:2( IPhone4 )
[2048, 1536] = 4:3
[1024, 768] = 4:3
Android Pad Resolution
[1920, 1080] = 16:9
[2048, 1536] = 4:3
[2560, 1600] = 16:10
[1280, 800] = 16:10
[1024, 600] = 16:9.375
2、预备定义
定义设计分辨率DesignResolution为(DesignWidth, DesignHeight)、设备分辨率Deviceresoluiton为(DeviceWidth,DeviceHeight)
3、原有方案
我们第一版的设计方案有两个:
a) 控件的缩放比例为min( DeviceWidth/DesignWidth, DeviceHeight/DesignHeight ), 在顶层Scene设置Scale。
b) 控件的缩放比例为min( DeviceWidth/DesignWidth, DeviceHeight/DesignHeight ), 每个控件单独设置缩放比。
背景画面按照非等比例拉伸填充整个设备画面。
Scalex = DeviceWidth/DesignWidth
Scaley = DeviceHeight/DesignHeight
控件位置进行调整
position.x = position.x * DeviceWidth/DesignWidth
position.y = position.y * DeviceHeight/DesignHeight
第一个方案的问题是画面只能是设计分辨率的缩放比,多出的画面部分将绘制黑边。下图为设备分辨率单纯拉伸宽度的情况。
第二个方案解决了缩放比的问题, 使得画面填充了整个设备空间。但是可能会造成控件之间的裂缝问题。对于需要紧密布局的界面是没办法保证在不同设备上的一致性的。如下图
三、新的方案
为解决旧有方案中的问题,本文提出了一个新的方案。新的方案完美解决了旧有方案的所有问题。同时满足了UE对布局的设计和要求。
首先需要定义一个中间分辨率——布局分辨率(LayoutResolution)。布局分辨率与设备分辨率等比例缩放。为保证美术在横向设计上的布局完全不变,布局分辨率的Width (LayoutWidth) = DesignWidth。如图:
最后一步布局分辨率到设备分辨率的切换很简单,只要在cocos中将DesignResolution设置成布局分辨率LayoutResolution,其他跟EXACT_FIT的布局方案,在底层Viewport的时候设置成DeviceResolution的大小即可实现了最后一步的缩放方案。
在DesignResolution到LayoutResolution的处理稍微复杂一些。
首先,我们需要对每个控件定义它的布局类型,布局类型有两种,一种是位置的布局类型(PositionLayoutType),另一种是大小的布局类型(SizeLayoutType)。
PositionLayoutType可支持的定义有:
cc.NODEPOSITIONLAYOUTTYPE_LB
cc.NODEPOSITIONLAYOUTTYPE_LT
cc.NODEPOSITIONLAYOUTTYPE_RT
cc.NODEPOSITIONLAYOUTTYPE_RB
cc.NODEPOSITIONLAYOUTTYPE_CE
cc.NODEPOSITIONLAYOUTTYPE_SCALABLE
PositionLayoutTYpe的前5种定义是相对位置的定义,LB、LT、RT、RB、CE分别表示左下角、左上角、右上角、右下角和中点位置。设参考位置点为RefPos,以上公式可以描述为:
cc.NODEPOSITIONLAYOUTTYPE_XX:
Node.x – RefPos.x=NodeNew.x – RefPosNew.x
Node.y – RefPos.y=NodeNew.y – RefPosNew.y
以上类型有效解决了布局之间的拼缝问题,两个Node只要参考点是一致的,那么他们之间的距离就是一个定值。
cc.NODEPOSITIONLAYOUTTYPE_SCALABLE表示Node的位置与设计分辨率的比值是定值。可以描述为:
cc.NODEPOSITIONLAYOUTTYPE_SCALABLE:
Node.x/DesignWidth= NodeNew.x/DesignWidth
Node.y/DesignHeight= NodeNew.y/DesignHeight
SizeLayoutType可支持的定义有:
cc.NODESIZELAYOUTTYPE_EXACTFIT
cc.NODESIZELAYOUTTYPE_SCALABLE
cc.NODESIZELAYOUTTYPE_EXACTFIT可以描述为
Node.ScaleX = NodeNew.ScaleX
Node.ScaleY = NodeNew.ScaleY
cc.NODESIZELAYOUTTYPE_SCALABLE可以描述为
NodeNew.ScaleX= Node.ScaleX * LayoutWidth/DesignWidth
NodeNew.ScaleY= Node.ScaleY * LayoutHeight/DesignHeight
以上类型用于解决部分Node需要大小布局跟设备成比例的缩放(即该Node可以接受不等比例缩放,比如背景图)
为方便上层设计者对底层结点透明,我们将以上所有公式描述全部写到Node的结点的setPosition、getPosition等函数,set类函数是Node->NodeNew的转换, get类函数式NodeNew->Node的转换。同时为方便编辑我们在cocosstudio的解析器中加入了对名字的解析,用户就可以在控件名字中定义布局类型了。(因为木有cocosstudio的代码,只能在名字上做技巧)。
四、展望
字体在不同设备上的缩放一直是一个问题,被缩放后的字体通常会变形的狠明显。我们可以在字体中特殊处理,讲字体在不同分辨率下底层进行自适应缩放。