Unity屏幕自适应原理
本节记录内容来自于siki学院的“暗黑战神”系列
先讲一下自适应问题的来源:
如上图所示,我们现在的画布里有两个按钮,且当前屏幕分辨率设为了1334*750。
假如我们改变一下屏幕分辨率,改为2668*1500后,效果如下图所示:
这代表当我们实际使用不同尺寸的手机屏幕时,会出现图片显示不全的情况,显然这是不行的。
来看一下问题的根源:
如上图所示,左侧和右侧分别是当分辨率被设为1334*750和2668*1500时对应的画布控件的Inspector面板,可以看到,随着分辨率的调节,画布的宽度和高度也被自动地调节了,这就是为什么会不匹配的原因,画布被自动调节到2倍宽高,两个按钮位置自然也不对了。
那么现在有两种解决方案:一是当分辨率改变时,让画布进行特定的缩放,而不是死板地只让画布的宽高与分辨率相同。二是让两个按钮维持原先大小,但移动位置,仍旧固定在左下角和右上角。我们应该用哪一种呢?
先看第一种,第一种方案主要通过修改上图中的Canvas Scaler(Script)面板来实现,比如:
如上面两张图所示,此时我们调节了Scale Factor为2,可以看到虽然屏幕分辨率为2668*1500,但显示仍旧正常,再仔细看一下,发现此时画布的宽高为1334*750,而不是2668*1500,已经与屏幕分辨率不同了,这个Scale Factor可以使你的画布的宽高与屏幕分辨率保持一个固定比例。
显然,利用这个Scale Factor,假如我们写一个脚本,获取屏幕的分辨率,然后算出一个相对我们设计时参考屏幕尺寸的比值,然后对应去修改Scale Factor,可以完成方案一。
但其实Unity有内置的机制来完成方案一:在Canvas Scaler(Script)面板中,有个UI Scale Mode选项卡,可以选Scale With Screen Size(默认为Constant Pixel Size),意思是根据实际屏幕的尺寸来自动调节画布缩放因子Scale Factor,选择后要设置一个参考尺寸,下面有个Match选项,可以选择是以高度还是宽度为参考,如下图所示:
比如这里设置了参考尺寸是1334*750,而且是以高度为参考,意思是当实际屏幕尺寸不等于参考尺寸的高度(这里是750)时,会按比例设置缩放因子。这时如果再调节分辨率为2668*1500,由于1500/750=2,相当于自动设置了缩放因子为2,因此会发现完美适配,对应的画布宽高仍为1334*750。
但这就带来了新的问题,缩放因子是以宽或高中的一种作为参考来设置的,如果像上面那样,等比例缩放还好,假若宽高比不同呢?比如若屏幕分辨率是1024*768,按照之前的说法,此时画布的宽度会变成1024/(768/750)=1000,高度为750,我们来验证一下:
如上图所示,画布的宽度变成了999.9999近似1000,没问题。
但很明显,现在这个策略就会出现问题,等比例缩放后两个按钮已经看不到了,怎么办呢?
显然,这就必须要配合第二种方案,即让两个按钮位置移动,维持在两个角落。
在说第二种方案前,先要考虑这样一个问题:自适应的时候能不能只使用第二种方案,也就是说只固定两个按钮到边界的距离,完全不用第一种方案,不使用缩放?
答案是不行,仔细想想就知道,这样就会出现屏幕尺寸整体扩大后,两个按钮显得过小的问题,所以缩放是必须要的。
那么到底应该以宽度为准,还是以高度为准?
我们知道,当前的手机屏幕,各种不同大小屏幕的手机,在竖屏高度上差别挺大的,在宽度上变化就小很多。那么对应的,当设计横屏游戏时,可以认为不同机型的横屏宽度变化很大,高度变化很小。那么显然我们以高度为缩放标准更合适,这样不同机型的缩放程度也就不大,对应UI的尺寸变化也就不大,当然,同理地,当设计竖屏游戏时,就应该以宽度为缩放标准。
那我们已经决定了在设计横屏游戏时以高度为缩放基准,那么就要解决之前说的实际宽高比与基准宽高比不同的问题了。
这个问题可以通过设置锚点来解决,如下图所示:
对左下角的按钮,设置锚点在左下角,右上角的设置在右上角即可,此时效果如下:
可以看到,即使在1024*768的分辨率下,依旧适配良好。
但需要注意的一点是,实际开发中,会有很多界面,比如登录界面,注册界面等等,为了更好的区分这些界面,防止不同界面的UI发生混淆,通常的手法是在场景中创建一个空物体,把该界面的UI元素都挂载到该空物体下,这样当开发下一个界面时,我们只需要简单地让开发好的界面的空物体不显示即可。如下图所示,panel就是那个空物体
但这样会在屏幕适配的时候碰到问题,如果把两个Button分别锚定到左上角和右下角,会固定到它们的父物体上,也就是这个panel空物体上,显然这样就无法固定到左下角和右上角了。
解决的方案是把这个空物体铺满整个画布,操作如下图所示:
为空物体选择伸展方式后,记得设置左右上下为0,这代表该物体离父物体(这里是画布)的左,右,上,下边的距离,设为0就是完全铺满画布。这样就完成了,具体效果图就不展示了,完美自适应。
这样就结束了吗?NoNoNo。
对于普通控件,这样无疑已经够了,但假如我们在界面里放了张背景图,这个图片作了以高度为基准的自适应,且用锚点铺满了整个画布。这个时候假如屏幕的高度发生了变化,按照之前说的,若以高度为基准,则高度不变,画布会自动对宽度进行缩放,而这时由于背景图片已经被锚定铺满了整个画布,因此背景图片会出现拉伸或压缩。这会影响观感,该怎么办呢?
通常的实际项目开发做法如下:对界面中的其它元素,仍按之前说的,用空物体容纳,空物体锚定并铺满画布,这些元素就锚定到空物体上。而对于背景图,则特殊处理,不要让它锚定并铺满画布,而是让它使用默认的铺展方式,即居中,如下图所示:
而且这个背景图需要做得比画布更大一些,假设是以高度为基准的缩放,那么此时高度会一直维持,宽度会根据屏幕进行缩放,所以只需要把背景图的宽度做得比参考尺寸大即可,这样,一开始我们不会展示全部的背景图,当屏幕的高度发生改变时,比如高度变小了,按之前说的,由于是高度为基准,因此画布会进行缩放,即高度维持基准值,而为了保证宽高比不变,必然导致画布宽度增大。就可以展示更多的内容,而且不会有图片被压缩的问题。
示意图如下:
最上面一张是初始图,此时分辨率为1334*750,背景的红色图片高度与画布相同,宽度要大于画布,此时仅展示了一部分背景。
下面两张图是把屏幕高度调节后的结果图,左边那张是把高度调低了,此时由于以高度为基准缩放的原因,画布高度一致保持不变,为了保持宽高比,画布的宽度会增加,到超过极限后画布的宽度会大于背景图的宽度,导致显示出问题,因此设计背景图大小时要注意,预留出的宽度(以高度为缩放基准的情况下)要考虑到屏幕的极限情况,保证预留宽度要满足即使在实际屏幕宽高比最极限的情况下图片也能正常显示。
同理,右边那张就是高度调高后的情况,调高后为了让画布高度保持不变,在宽高比的限制下会导致宽度减小,就是右图的样子了。
完毕。