适配多分辨率绝笔是头疼的事没有之一。这两天,在研究这块。趟过的坑如下:
注:项目的ui主要分为场景(场景间切换,只有一个)和弹窗可以打开多个。下文控件的anchor(定位?)默认是用控件自带的。如下图:
1.一般弹窗打开都有有动画,例如缩放动画等。当弹窗内的控件有anchor,由于anchor执行是在update里执行的(anchor的类型分为onEnable和onUpdate,顾名思义,前者在OnEnable中判断(非执行),后者在OnUpdate中判断,均在Update中执行,只是前者执行一次,后者每桢调用,见UIRect的Update(),代码如下),当anchor为onEnable,弹窗打开(gameObject.active=true后),就播放动画,比如先设置缩放值,比如0.5的之后,打开后会发现anchor元素是错乱的。究其原因是因为,anchor的执行在Update处执行,从而导致先缩放了界面,再执行anchor元素。当anchor=onUpdate时,元素位置正确,但是有两个缺点,一是比较耗,二是不能整体缩放,因为各个元素可能anchor到不同的节点。
public void Update ()
{
if (!mAnchorsCached) ResetAnchors();
int frame = Time.frameCount;
#if UNITY_EDITOR
if (mUpdateFrame != frame || !Application.isPlaying)
#else
if (mUpdateFrame != frame)
#endif
{
#if UNITY_EDITOR
if (updateAnchors == AnchorUpdate.OnUpdate || mUpdateAnchors || !Application.isPlaying)
#else
if (updateAnchors == AnchorUpdate.OnUpdate || mUpdateAnchors)
#endif
UpdateAnchorsInternal(frame);
// Continue with the update
OnUpdate();
}
}
解决方法如下,将动画播放放在LateUpdate中执行,即可。这样保证元素先anchor后,在缩放整体ui,无任何问题。
protected virtual void LateUpdate()
{
if (!isOpened)
{
isOpened = true;
anim.Open();
}
}
通过上述内容,会发现anchor格外蛋疼,要十分注意到这个执行顺序。
2.anchor 做的简单的,都是将元素向四周拉,元素的大小是根据uiroot自动缩放的。项目测试的分辨率是16:9,16:10,及4:3。4:3变化巨大,实在想不到什么好的适配法则。美术的需求,希望有些面板,比如背包区域等,可以自动上下、左右拉伸,即4:3可以获得更大的显示区域。这类区域的排版一般都是用uiGrid,uiTable等实现的。uigrid没法anchor,在4:3下,位置完全不对。第一个想法是用UIAnchor这个脚本,然后就遇到了一个坑。这个UIAnchor是在Start执行的。然后anchor是在Update中执行的.....一起用就挂壁了。最后,uigrid也绑定空的uiwidget,然后做anchor,解决了这个问题。