Search Unity

Question C# scripting: how to account for different anchoring settings when moving/resizing a RectTransform?

Discussion in 'UGUI & TextMesh Pro' started by Sinterklaas, Feb 1, 2022.

  1. Sinterklaas

    Sinterklaas

    Joined:
    Jun 6, 2018
    Posts:
    93
    I'm trying to write a method that can move and resize a RectTransform to match another one, while leaving its pivot and anchoring intact. Rotation is not yet considered. Currently, I have this:
    Code (CSharp):
    1. /// <summary>
    2. /// Moves and resizes a RectTransform to match another one, while leaving its pivot and
    3. /// anchoring intact.
    4. /// </summary>
    5. public static void Match(RectTransform src, RectTransform dst)
    6. {
    7.     // Get dst world-space corners.
    8.     Vector3[] dstCorners = new Vector3[4];
    9.     dst.GetWorldCorners(dstCorners);
    10.  
    11.     // Calculate dst world-space size and center from corners.
    12.     Vector2 dstSize = (Vector2)dstCorners[2] - (Vector2)dstCorners[0];
    13.     Vector2 dstCenter = (Vector2)dstCorners[0] + dstSize / 2f;
    14.  
    15.     // Get src pivot location relative to src center.
    16.     Vector2 pivotOffset = src.pivot - Vector2.one * 0.5f;
    17.  
    18.     // Check if src anchors are together on x and y axes (currently unused).
    19.     bool anchorsTogetherX = src.anchorMin.x == src.anchorMax.x;
    20.     bool anchorsTogetherY = src.anchorMin.y == src.anchorMax.y;
    21.  
    22.     // Calculate src target position.
    23.     Vector2 targetPos = dstCenter + dstSize * pivotOffset;
    24.  
    25.     // Set src position and size delta.
    26.     src.position = new Vector3(targetPos.x, targetPos.y, src.position.z);
    27.     src.sizeDelta = dstSize / src.lossyScale;
    28. }
    Which works well, except when the anchors of the src RectTransform are not together on the x and/or y axes. So in other words, the method doesn't work for stretching anchor settings. RectTransforms end up much wider or taller than they should be, which makes sense, as the sizeDelta works differently in these cases (though It's not entirely clear to me what exactly the variable does in these cases; the documentation is unfortunately a bit confusing for me).

    Does anyone know how one should respond to the situations where the anchors are not placed together on one or both axes, so that the method will work for any anchoring setting (including custom ones)?
     
  2. Sinterklaas

    Sinterklaas

    Joined:
    Jun 6, 2018
    Posts:
    93
    Ok, for anyone else who's trying to do this: the following code worked for me in all the edge cases that I tested it for. It's pretty much the same code as before, except that RectTransform.SetSizeWithCurrentAnchors is called to correct the sizeDelta whenever anchors are not placed together on an axis.
    Code (CSharp):
    1. /// <summary>
    2. /// Moves and resizes a RectTransform to match another one, while leaving its pivot and
    3. /// anchoring intact.
    4. /// </summary>
    5. public static void Match(RectTransform src, RectTransform dst)
    6. {
    7.     // Get dst world-space corners.
    8.     Vector3[] dstCorners = new Vector3[4];
    9.     dst.GetWorldCorners(dstCorners);
    10.  
    11.     // Get dst world-space size and center.
    12.     Vector2 dstSize = (Vector2)dstCorners[2] - (Vector2)dstCorners[0];
    13.     Vector2 dstCenter = (Vector2)dstCorners[0] + dstSize / 2f;
    14.  
    15.     // Get src pivot location relative to src center.
    16.     Vector2 pivotOffset = src.pivot - Vector2.one * 0.5f;
    17.  
    18.     // Check if src anchors are together on x and y axes.
    19.     bool anchorsTogetherX = src.anchorMin.x == src.anchorMax.x;
    20.     bool anchorsTogetherY = src.anchorMin.y == src.anchorMax.y;
    21.  
    22.     // Calculate src target position.
    23.     Vector2 targetPos = dstCenter + dstSize * pivotOffset;
    24.  
    25.     // Set src position and size delta.
    26.     src.position = new Vector3(targetPos.x, targetPos.y, src.position.z);
    27.     src.sizeDelta = dstSize / src.lossyScale;
    28.  
    29.     // Handle cases where anchors were not together by forcing the size to a value.
    30.     if (!anchorsTogetherX)
    31.         src.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, src.sizeDelta.x);
    32.     if (!anchorsTogetherY)
    33.         src.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, src.sizeDelta.y);
    34. }