Unity UI ---- RectTransform

想要所有子物体等于缩放:Achors 和 Pivot

子物体锚定 一个父物体的 百分比坐标,这样会保证子物体跟随父物体等比缩放。所以说,当父物体的缩放出问题了,子物体就算锚定对了也会出问题。注意子物体锚定的时候用的是自身坐标,而非父物体的坐标。

最简单便于理解 和 直观的操作:把pivot全设置到左下角。如图:123正方形image。

1的RectTransform:(注意pivot和anchor,很一般,都是默认的)

2 和 3 的

 几乎一模一样。pivot都在左下角,anchor的min和max 分别就是:x:0_0.5   y:0.5_1     了。很明显能看出来,min和max的意思就是,以自身的pivot为起点,锚定到父物体大小的百分比。

进而知道这个特性后,其实有个特别好的ui流程:

先试用这种锚定方式(很直观的把UI拼好),然后写个工具在编辑器下或者加载的时候实时算出 要等比缩放的物体 在锚定在父物体的位置。

设置position时从父物体递归,因为,子物体都是相对位置。

设置anchor时从子物体开始递归设置,因为子物体的RectTransform依赖父物体的,一旦设置了父物体的rect,子物体获取的数据就无法保证计算一致。

统一处理的代码:

public partial class BuildingWindowEditor
{
    RectTransform[] rts;
    GameObject go;
    Dictionary<Transform, Vector3> cache = new Dictionary<Transform, Vector3>();
    private void BuildingUI()
    {
        GUILayout.Box("设置 选中的UI的子物体 跟随选中节点进行等比缩放。");
        if (GUILayout.Button("access"))
        {
            cache.Clear();
            go = Selection.activeGameObject;
            if (go == null)
            {
                Debuger.LogError(" selection is null");
                return;
            }
            rts = go.GetComponentsInChildren<RectTransform>(true);

            foreach (var item in rts)
            {
                var prt = item.parent.GetComponent<RectTransform>();
                if (prt == null)
                {
                    continue;
                }
                Vector2 parentPivot = prt.pivot;
                Vector2 curPivot = item.pivot;
                Vector3 deltaPos = item.position - prt.position;
                Vector3 delta = new Vector3(parentPivot.x * prt.rect.width, parentPivot.y * prt.rect.height, 0) -
                                new Vector3(curPivot.x * item.rect.width, curPivot.y * item.rect.height, 0) + deltaPos;
                cache.Add(item, delta);
            }

            RemakeChildPos(go.GetComponent<RectTransform>());
            RemakChildAnchor(go.GetComponent<RectTransform>(), null);
        }
    }


    void RemakeChildPos(RectTransform cur)
    {
        if (cur == null || !cache.ContainsKey(cur))
        {
            return;
        }

        var prt = cur.parent.GetComponent<RectTransform>();

        cur.pivot = Vector2.zero;
        cur.position = cache[cur] + prt.position;

        for (int i = 0; i < cur.childCount; i++)
        {
            RemakeChildPos(cur.GetChild(i).GetComponent<RectTransform>());
        }
    }

    void RemakChildAnchor(RectTransform cur, RectTransform parent)
    {
        if (cur == null)
        {
            return;
        }
        for (int i = 0; i < cur.childCount; i++)
        {
            RemakChildAnchor(cur.GetChild(i).GetComponent<RectTransform>(), cur);
        }

        if (cur.name == go.name)
        {
            return;
        }
        if (parent == null)
        {
            return;
        }

        Debuger.LogError(cur.name + "   ***   " + parent.name);

        float deltaX = (cur.position - parent.position).x;
        float deltaY = (cur.position - parent.position).y;

        Vector2 X = new Vector2(deltaX, deltaX + cur.rect.width) / parent.rect.width;
        Vector2 Y = new Vector2(deltaY, deltaY + cur.rect.height) / parent.rect.height;

        Debuger.LogError(string.Format("{0}   {1}   {2}   {3}   {4}", deltaX, deltaY, cur.rect, parent.rect, cur.localPosition));


        cur.anchorMin = new Vector2(X.x < X.y ? X.x : X.y, 
                                    Y.x < Y.y ? Y.x : Y.y);

        cur.anchorMax = new Vector2(X.x > X.y ? X.x : X.y, 
                                    Y.x > Y.y ? Y.x : Y.y);

        cur.offsetMin = Vector2.zero;
        cur.offsetMax = Vector2.zero;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值