固定ui大小_LayoutGroup初体验——按比例而不是按固定值适配的Anchor

本文介绍了如何使用Unity的LayoutGroup组件实现按比例而非固定值进行UI适配,探讨了Anchor的工作原理,并分享了一个实验性的功能实现。通过调整子节点的位置和大小,实现了动态布局。同时,讨论了Scale对UI性能的影响,提出了关于Scale是否影响DrawCall的疑问。
摘要由CSDN通过智能技术生成

跳转至专题目录

专题推荐文章

  1. localPosition与anchoredPosition转化
  2. unity Scene View扩展之编辑器扩展总结
  3. Unity获取鼠标点击ui GameObject

本系列目录

  1. unity ugui Layout学习之Layout相关类入门介绍
  2. LayoutGroup初体验——按比例而不是按固定值适配的Anchor

LayoutGroup的一些属性方法就不详细说了,毕竟网上资料挺多的,重复造轮子的活。

这里主要描述一下,使用LayoutGroup,完成我一个脑洞的过程。

最开始,在做一个ui适配,意识到Anchor只是到锚点的固定距离适配,并不是按比例来实现适配,也不会修改ui元素的大小,这种效果类似Scale效果。

但是我又想起了刚毕业时,我老大跟我说,改ui大小不要用Scale,要去改width和height,或者说去改offsetMax和offsetMin。

虽然说并不是一个很复杂的需求,但想到了最近在看的Auto Layout System,就拿来试一试吧。

7011e1b8bee596e2a2e108b4b0272500.gif
红色图片的锚点在左上方,距离是固定了,但并不是等比例缩放

ddfeedc3f667532886a77c2bce3abada.gif
scale效果,是按比例缩放的

虽然不打算详细说,但也大概说一下用到的两个接口方法SetLayoutHorizontal ,SetLayoutVertical 的定义吧

  1. 如果RectTransform被修改时, Auto Layout System会先调用SetLayoutHorizontal,然后再调用SetLayoutVertical
  2. SetLayoutHorizontal会在这个子RectTransform允许调用LayoutUtility.GetMinWidth, LayoutUtility.GetPreferredWidth, and LayoutUtility.GetFlexibleWidth时被调用
  3. SetLayoutVertical 会在这个子RectTransform允许调用 LayoutUtility.GetMinHeight, LayoutUtility.GetPreferredHeight, and LayoutUtility.GetFlexibleHeight时被调用
  4. 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
功能实现效果

功能是初步实现了,不过是个实验性质的功能,也许有更好的方法实现,也许用LayoutGroup还有更简单的实现方法,不过在开发过程中也了解到了一些UGUI的知识了,也是值得高兴的事。

不过,最开始我以为ui不要设置Scale,是因为合批问题,但后来我试验了一下,改了ui的Scale值,drawcall并不会增加。。。

至于ui设置Scale有没有什么性能消耗,我暂时不了解,不知道有没有人帮我解答一下疑惑=。=

github地址

Zhunity/UnityPractice​github.com
54aadf4583a8e49fb753029f2eb750c9.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值