Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Encapsulate child RectTransforms?

Discussion in 'Scripting' started by Noblauch, Aug 18, 2020.

  1. Noblauch

    Noblauch

    Joined:
    May 23, 2017
    Posts:
    256
    Math-Experts, hear me! (Brain-Teaser ahead!)

    I'm basically trying to build a working content size fitter. A component, that resizes its own rect transform according to the encapsulated sum of all children rect transforms. And yes, I guess the Unity Content Size Fitter should do this, but it's just does nothing.

    Well, I'd say I'm pretty close, and already thought it would be working, but sometimes it is behaving strange and I don't know why.
    Here is what I want (grey are children, red their pivot points, green the desired result):
    Encapsulate.jpg
    The Green box is what I want to get, just encapsulate all child transform, no matter their internal scale or pivot. just the "real" bounds.

    This is my code so far:
    Code (CSharp):
    1.     [ExecuteInEditMode]
    2.     [RequireComponent(typeof(RectTransform))]
    3.     public class ContentSizeMimic : UIBehaviour, ILayoutSelfController
    4.     {
    5.         private RectTransform[] _childTransforms;
    6.  
    7.         private RectTransform _myRect;
    8.         private RectTransform RectTransform => _myRect == null ? GetComponent<RectTransform>() : _myRect;
    9.  
    10.         protected override void Awake()
    11.         {
    12.             base.Awake();
    13.             _childTransforms = GetComponentsInChildren<RectTransform>().Where(rect => rect.gameObject != this.gameObject).ToArray();
    14.         }
    15.      
    16.         // ToDo: potential performance issue
    17.         private void Update() => CalculateParentRect();
    18.      
    19.         private void CalculateParentRect()
    20.         {
    21.             // If any child got deleted, fetch children again
    22.             if (_childTransforms.Any(c => c == null))
    23.                 _childTransforms = GetComponentsInChildren<RectTransform>().Where(rect => rect.gameObject != this.gameObject).ToArray();
    24.          
    25.             // Using Vector4 to store: minX, maxX, minY, maxY
    26.             Vector4 xXyY = new Vector4(float.MaxValue, float.MinValue, float.MaxValue, float.MinValue);
    27.             foreach (var childRect in _childTransforms)
    28.             {
    29.                 // Check for minimum X
    30.                 if (childRect.rect.xMin < xXyY.x)
    31.                     xXyY.x = childRect.rect.xMin;
    32.              
    33.                 // Check for maximum X
    34.                 if (childRect.rect.xMax > xXyY.y)
    35.                     xXyY.y = childRect.rect.xMax;
    36.              
    37.                 // Check for minimum Y
    38.                 if (childRect.rect.yMin < xXyY.z)
    39.                     xXyY.z = childRect.rect.yMin;
    40.              
    41.                 // Check for maximum Y
    42.                 if (childRect.rect.yMax > xXyY.w)
    43.                     xXyY.w = childRect.rect.yMax;
    44.             }
    45.          
    46.             Vector2 encapsulatingSize = new Vector2(Mathf.Abs(xXyY.y - xXyY.x), Mathf.Abs(xXyY.w - xXyY.z));
    47.             if (RectTransform.sizeDelta.x != encapsulatingSize.x || RectTransform.sizeDelta.y != encapsulatingSize.y)
    48.             {
    49.                 Log.Unicorn("This is called too often");
    50.                 RectTransform.sizeDelta = encapsulatingSize;
    51.                LayoutRebuilder.MarkLayoutForRebuild(RectTransform);
    52.             }
    53.         }
    54.  
    55.         // From ILayoutSelfController Interface
    56.         public void SetLayoutHorizontal() { }
    57.         public void SetLayoutVertical() { }
    58.     }
    What am I doing wrong? Obviously RectTransform.rect.xMax is not giving me the furthest point to the right on the world x-axis.
     
    Last edited: Aug 18, 2020
    eses likes this.
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,697
    unity's Content Size fitter only really works if the children have Layout Element components I think. Have you tried adding that? (Sorry this isn't an answer to your actual question)
     
  3. Noblauch

    Noblauch

    Joined:
    May 23, 2017
    Posts:
    256
    If that would work, this would solve my problem as-well. But I tried almost everything to make it do something. Just tried adding Layout Element components to the children, but it still doesn't resize.
    Also I'm getting a warning that I shouldn't do that, because the parent element is a layout group (vertical) but this is all the reason I need to resize it in the first place ._.
     
  4. Noblauch

    Noblauch

    Joined:
    May 23, 2017
    Posts:
    256
    Anyone? We are still facing this issue on a regular basis, and have very ugly dirty workarounds to get our layout groups to behave as desired.