Unity:使 parent 的大小适合孩子的大小

Unity: Fit size of parent to size of childs

我在 Canvas 中有一个空的,它有多个 objects 作为 children。随着游戏的进行,更多 children 被添加到 parent。我希望 parent 的大小适合其 children。

我已经阅读了很多关于这个主题的文章,但每次我遇到 ContentSizeFitter,不幸的是它对我不起作用,因为它需要一个布局组,而我没有,因为 children 没有订单,乱放

我使用的是 Unity 2018.3.4f1 个人版。

未调整大小parent:

尺码parent(红色:新,绿色:旧):

结构:

Canvas
 |- Empty
     |- Child 1
     |- Child 2
     |- Child X

我想你可以找到最左边框和最右边框,然后将那个值的差值添加为父 RectTransformsizeDelta

这应该固定大小(重复 Y 的顶部和底部)。

对于可以在 Vector2 中获得最左边框和上边框的左上角的位置,然后将该向量设置为 anchoredPosition 到父 RectTransform

请注意,父级的枢轴必须位于左上角才能正常工作。

这段代码只是接近了一些东西,但还不够好。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FitParentToChildren : MonoBehaviour
{
    #region INTERNAL

    public RectTransform parent;
    public RectTransform[] children;

    public float minX = 100000;
    public float maxX = -100000;
    public float minY = 100000;
    public float maxY = -100000;

    #endregion

    #region INITIALIZATION

    void Awake()
    {
        parent = GetComponent<RectTransform>();
        children = GetComponentsInChildren<RectTransform>();
    }

    void Start()
    {
        SetMinMaxValues();
        FitToChildren();
    }

    #endregion

    #region BEHAVIOURS

    private void FitToChildren()
    {
        parent.sizeDelta = GetNewRect();
        parent.anchoredPosition = GetTopLeftCornerPositon();
    }

    private void SetMinMaxValues()
    {
        for (int i = 1; i < children.Length; i++)
        {
            float tempMinX = children[i].anchoredPosition.x - children[i].sizeDelta.x / 2;
            if (tempMinX < minX) minX = tempMinX;

            float tempMaxX = children[i].anchoredPosition.x + children[i].sizeDelta.x / 2;
            if (tempMaxX > maxX) maxX = tempMaxX;

            float tempMinY = children[i].anchoredPosition.y - children[i].sizeDelta.y / 2;
            if (tempMinY < minY) minY = tempMinY;

            float tempMaxY = children[i].anchoredPosition.y + children[i].sizeDelta.y / 2;
            if (tempMaxY > maxY) maxY = tempMaxY;
        }
    }

    private Vector2 GetNewRect()
    {
        return new Vector2 (maxX - minX, maxY - minY);
    }

    private Vector2 GetTopLeftCornerPositon()
    {
        return new Vector2 (minX, maxY);
    }

    #endregion
}

GIF 在这里

像这样的东西应该有用。它循环遍历您选择的对象的所有子对象,然后找到这些对象的渲染器边界并更新最小值和最大值。在 Start() 函数的末尾,变量 min 和 max 保存定义边界的框角的坐标。

public class NewBehaviourScript : MonoBehaviour
{
    void Start ()
    {
        Vector2 min = new Vector2 (0, 0);
        Vector2 max = new Vector2 (0, 0);

        GetParentBounds (gameObject, out min, out max);
        Debug.Log (min);
        Debug.Log (max);

    }

    void GetParentBounds (GameObject GO, out Vector2 pMin, out Vector2 pMax)
    {
        Transform[] ts = GO.GetComponentsInChildren<Transform> ();

        Vector2 parentMin = new Vector2 (float.MaxValue, float.MaxValue);
        Vector2 parentMax = new Vector2 (float.MinValue, float.MinValue);

        foreach (Transform t in ts) {
            Renderer rend = t.GetComponent<Renderer> ();
            if (rend != null) {
                Vector2 min = rend.bounds.min;
                Vector2 max = rend.bounds.max;
                Debug.Log (string.Format ("[{0}, {1}], [{2}, {3}]", min.x, min.y, max.x, max.y));
                parentMin.x = Mathf.Min (parentMin.x, min.x);
                parentMin.y = Mathf.Min (parentMin.y, min.y);
                parentMax.x = Mathf.Max (parentMax.x, max.x);
                parentMax.y = Mathf.Max (parentMax.y, max.y);
            }
        }

        pMin = parentMin;
        pMax = parentMax;
    }
}

我已经编写了一小段代码来完成它的工作,或者按照我想要的方式来完成,这对我来说已经足够了:

using UnityEngine;

public class SizeFitter : MonoBehaviour {
    public void CheckForChanges() {
        RectTransform children = transform.GetComponentInChildren<RectTransform>();

        float min_x, max_x, min_y, max_y;
        min_x = max_x = transform.localPosition.x;
        min_y = max_y = transform.localPosition.y;

        foreach (RectTransform child in children) {
            Vector2 scale = child.sizeDelta;
            float temp_min_x, temp_max_x, temp_min_y, temp_max_y;

            temp_min_x = child.localPosition.x - (scale.x / 2);
            temp_max_x = child.localPosition.x + (scale.x / 2);
            temp_min_y = child.localPosition.y - (scale.y / 2);
            temp_max_y = child.localPosition.y + (scale.y / 2);

            if (temp_min_x < min_x)
                min_x = temp_min_x;
            if (temp_max_x > max_x)
                max_x = temp_max_x;

            if (temp_min_y < min_y)
                min_y = temp_min_y;
            if (temp_max_y > max_y)
                max_y = temp_max_y;
        }

        GetComponent<RectTransform>().sizeDelta = new Vector2(max_x - min_x, max_y - min_y);
    }
}
Bounds bound = new Bounds();
for (int i = 0; i < children.Length; ++i)
{
    RectTransform child = children[i];
    if (child != null && child.gameObject.activeSelf)
    {
        Vector2 pos = child.localPosition;
        Vector2 min = pos - child.sizeDelta * child.pivot;
        Vector2 max = min + child.sizeDelta;
        Bounds temp = new Bounds();
        temp.SetMinMax(min, max);
        bound.Encapsulate(temp);
    }
}