跳转至专题目录
专题推荐文章
- localPosition与anchoredPosition转化
- unity Scene View扩展之编辑器扩展总结
- Unity获取鼠标点击ui GameObject
本系列目录
- unity ugui Layout学习之Layout相关类入门介绍
- LayoutGroup初体验——按比例而不是按固定值适配的Anchor
LayoutGroup的一些属性方法就不详细说了,毕竟网上资料挺多的,重复造轮子的活。
这里主要描述一下,使用LayoutGroup,完成我一个脑洞的过程。
最开始,在做一个ui适配,意识到Anchor只是到锚点的固定距离适配,并不是按比例来实现适配,也不会修改ui元素的大小,这种效果类似Scale效果。
但是我又想起了刚毕业时,我老大跟我说,改ui大小不要用Scale,要去改width和height,或者说去改offsetMax和offsetMin。
虽然说并不是一个很复杂的需求,但想到了最近在看的Auto Layout System,就拿来试一试吧。
![7011e1b8bee596e2a2e108b4b0272500.gif](https://i-blog.csdnimg.cn/blog_migrate/91c494e29f6e2d7365bd8c9fd1dd52e0.gif)
![ddfeedc3f667532886a77c2bce3abada.gif](https://i-blog.csdnimg.cn/blog_migrate/064ec35a19e5433864d8b5b380065aa8.gif)
虽然不打算详细说,但也大概说一下用到的两个接口方法SetLayoutHorizontal ,SetLayoutVertical 的定义吧
- 如果RectTransform被修改时, Auto Layout System会先调用SetLayoutHorizontal,然后再调用SetLayoutVertical
- SetLayoutHorizontal会在这个子RectTransform允许调用LayoutUtility.GetMinWidth, LayoutUtility.GetPreferredWidth, and LayoutUtility.GetFlexibleWidth时被调用
- SetLayoutVertical 会在这个子RectTransform允许调用 LayoutUtility.GetMinHeight, LayoutUtility.GetPreferredHeight, and LayoutUtility.GetFlexibleHeight时被调用
- LayoutGroup会通过这个去决定它自己或者子RectTransform的width和height
所以我们把逻辑写在这两个地方就可以了
首先第一步,获取每个子节点左下角和右上角,到AnchorMin,AnchorMax点的距离,并把这个距离与当前节点的长宽的壁纸保存起来。
Dictionary<int, Vector2[]> childScales = new Dictionary<int, Vector2[]>(); // 比例保存地方
protected override void Awake()
{
base.Awake();
Vector2 size = rectTransform.rect.size;
// 获取左下角坐标
Vector3[] thisCorners = new Vector3[4];
rectTransform.GetWorldCorners(thisCorners);
Vector3 thisMinPos = thisCorners[0];
Vector3[] childCorners = new Vector3[4];
for (int i = 0; i < rectTransform.childCount; i++)
{
RectTransform child = rectTransform.GetChild(i).transform as RectTransform;
child.GetWorldCorners(childCorners);
var minCorner = childCorners[0];
var maxCorner = childCorners[2];
Vector2[] scales = new Vector2[2];
scales[0] = GetCornerScale(size, thisMinPos, minCorner, child.anchorMin);
scales[1] = GetCornerScale(size, thisMinPos, maxCorner, child.anchorMax);
childScales.Add(child.GetHashCode(), scales);
}
}
/// <summary>
/// 计算左下角和右上角到边缘的距离占比
/// </summary>
/// <param name="parentSize"></param>
/// <param name="parentMinCorner"></param>
/// <param name="corner"></param>
/// <param name="anchor"></param>
/// <returns></returns>
public Vector2 GetCornerScale(Vector2 parentSize, Vector3 parentMinCorner, Vector3 corner, Vector2 anchor)
{
var anchorPos = Vector2.Scale(anchor, parentSize);
var cornerPos = corner - parentMinCorner;
float x = (cornerPos.x - anchorPos.x) / parentSize.x;
float y = (cornerPos.y - anchorPos.y) / parentSize.y;
Vector2 scale = new Vector2(x, y);
return scale;
}
然后就是在那两个接口设置子节点的坐标和大小了
public override void SetLayoutHorizontal()
{
SetChildrenAlongAxis(0);
}
public override void SetLayoutVertical()
{
SetChildrenAlongAxis(1);
}
protected void SetChildrenAlongAxis(int axis)
{
Vector2 size = rectTransform.rect.size;
Vector2[] scales = new Vector2[2];
for (int i = 0; i < rectChildren.Count; i++)
{
RectTransform child = rectChildren[i];
if(!childScales.TryGetValue(child.GetHashCode(), out scales))
{
continue;
}
SetChildrenRect(size, child, scales[0], axis, false); // 设置子节点左下角坐标
SetChildrenRect(size, child, scales[1], axis, true); // 设置子节点右上角坐标
}
}
public void SetChildrenRect(Vector2 parentSize, RectTransform child, Vector2 scale, int axis, bool isMax)
{
float scaleAxisValue = scale[axis];
Vector2 anchor = isMax ? child.anchorMax : child.anchorMin;
float anchorPos = anchor[axis] * parentSize[axis];
float cornerPos = scaleAxisValue * parentSize[axis] + anchorPos;
Vector2 offset;
if (isMax)
{
// 根据比例算出最大值坐标
offset = child.offsetMax;
offset[axis] = cornerPos - parentSize[axis];
child.offsetMax = offset;
}
else
{
// 根据比例算出最小值坐标
offset = child.offsetMin;
offset[axis] = cornerPos;
child.offsetMin = offset;
}
}
![33225c267fbfef4a7a5ba8e50029a5da.gif](https://i-blog.csdnimg.cn/blog_migrate/2586d8b8cb52fc4efaa7a6a0d632bc99.gif)
功能是初步实现了,不过是个实验性质的功能,也许有更好的方法实现,也许用LayoutGroup还有更简单的实现方法,不过在开发过程中也了解到了一些UGUI的知识了,也是值得高兴的事。
不过,最开始我以为ui不要设置Scale,是因为合批问题,但后来我试验了一下,改了ui的Scale值,drawcall并不会增加。。。
至于ui设置Scale有没有什么性能消耗,我暂时不了解,不知道有没有人帮我解答一下疑惑=。=
github地址
Zhunity/UnityPracticegithub.com![54aadf4583a8e49fb753029f2eb750c9.png](https://i-blog.csdnimg.cn/blog_migrate/181f2f1db9957f439837efa2c8dbe253.png)