Search Unity

Code Snippet: Size RawImage to Parent, keep aspect ratio.

Discussion in 'Unity UI (uGUI) & TextMesh Pro' started by shawnblais, Jan 24, 2016.

  1. shawnblais

    shawnblais

    Joined:
    Oct 11, 2012
    Posts:
    215
    Here's a handy little script I came up with, so you can tell any RawImage to fill it's parent's Rect, while maintaining the aspect ratio of the src texture. It also supports %-based padding, and images that have been rotated by 90 degree increments.
    Code (csharp):
    1.  
    2. static class CanvasExtensions {
    3.     public static Vector2 SizeToParent(this RawImage image, float padding = 0) {
    4.         var parent = image.transform.parent.GetComponent<RectTransform>();
    5.         var imageTransform = image.GetComponent<RectTransform>();
    6.         if (!parent) { return imageTransform.sizeDelta; } //if we don't have a parent, just return our current width;
    7.         padding = 1 - padding;
    8.         float w = 0, h = 0;
    9.         float ratio = image.texture.width / (float)image.texture.height;
    10.         var bounds = new Rect(0, 0, parent.rect.width, parent.rect.height);
    11.         if (Mathf.RoundToInt(imageTransform.eulerAngles.z) % 180 == 90) {
    12.               //Invert the bounds if the image is rotated
    13.               bounds.size = new Vector2(bounds.height, bounds.width);
    14.         }
    15.         //Size by height first
    16.         h = bounds.height * padding;
    17.         w = h * ratio;
    18.         if (w > bounds.width * padding) { //If it doesn't fit, fallback to width;
    19.             w = bounds.width * padding;
    20.             h = w / ratio;
    21.         }
    22.         imageTransform.sizeDelta = new Vector2(w, h);
    23.         return imageTransform.sizeDelta;
    24.     }
    25. }
    26.  
    Usage:
    Code (csharp):
    1. rawImage.SizeToParent();
    This is mostly useful for when you're loading a bunch of external images into a container, w/ random aspect ratios, and want them to fill the available space, without losing aspect ratio. The Image control is has a similar API, but requires you create a new Sprite() everytime you swap textures, which is a major performance drain.
     
    Last edited: Jun 20, 2019
  2. Freezy

    Freezy

    Joined:
    Jul 15, 2012
    Posts:
    232
    Thank you for sharing, this saved me some time ;-)
    I did make some adjustments, enjoy !


    Code (CSharp):
    1.    
    2. public static Vector2 SizeToParent(this RawImage image, float padding = 0) {
    3.         float w = 0, h = 0;
    4.         var parent = image.GetComponentInParent<RectTransform>();
    5.         var imageTransform = image.GetComponent<RectTransform>();
    6.  
    7.         // check if there is something to do
    8.         if (image.texture != null) {
    9.             if (!parent) { return imageTransform.sizeDelta; } //if we don't have a parent, just return our current width;
    10.             padding = 1 - padding;
    11.             float ratio = image.texture.width / (float)image.texture.height;
    12.             var bounds = new Rect(0, 0, parent.rect.width, parent.rect.height);
    13.             if (Mathf.RoundToInt(imageTransform.eulerAngles.z) % 180 == 90) {
    14.                 //Invert the bounds if the image is rotated
    15.                 bounds.size = new Vector2(bounds.height, bounds.width);
    16.             }
    17.             //Size by height first
    18.             h = bounds.height * padding;
    19.             w = h * ratio;
    20.             if (w > bounds.width * padding) { //If it doesn't fit, fallback to width;
    21.                 w = bounds.width * padding;
    22.                 h = w / ratio;
    23.             }
    24.         }
    25.         imageTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, w);
    26.         imageTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, h);
    27.         return imageTransform.sizeDelta;
    28.     }
    29.  
     
  3. elpuerco63

    elpuerco63

    Joined:
    Jun 26, 2014
    Posts:
    271
    Have tried this in various ways but I keep getting null reference on line: 4?
     
  4. Freezy

    Freezy

    Joined:
    Jul 15, 2012
    Posts:
    232
    var parent = image.transform.parent.GetComponentInParent<RectTransform>();

    Is the raw Image parented to an object with a recttransform?
     
    elpuerco63 likes this.
  5. elpuerco63

    elpuerco63

    Joined:
    Jun 26, 2014
    Posts:
    271
    DOH!!!! had script attached to wrong GO....!
     
    Freezy likes this.
  6. NorthStar79

    NorthStar79

    Joined:
    May 8, 2015
    Posts:
    79
    works like a charm, Thanks!
     
  7. lumoconnor

    lumoconnor

    Joined:
    Jan 17, 2016
    Posts:
    22
    Hey, thanks for this code. Its very useful, however, I think I found a bug.

    GetComponentInParent() returns a component on this game object or its parents. So, in my case it was returning the RectTransform of the image itself instead of the parent rect. Super annoying. Here's the documentation:
    https://docs.unity3d.com/ScriptReference/GameObject.GetComponentInParent.html

    A fix - change line 3 to...
    Code (CSharp):
    1. var parent = image.transform.parent.GetComponent<RectTransform>();
     
  8. BreynartStudios

    BreynartStudios

    Joined:
    Feb 3, 2018
    Posts:
    3
    I really appreciate it!!! Works flawlessly :)
     
  9. shawnblais

    shawnblais

    Joined:
    Oct 11, 2012
    Posts:
    215
    Fixed. Better late than never :)
     
unityunity