Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Any easy way to make an Image fill its space without stretching?

Discussion in 'UGUI & TextMesh Pro' started by JoeStrout, Aug 3, 2015.

  1. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    This seems like it should be simple, but I can't see it:

    I just want my background image to fill the screen (or in general, for any image to fill its bounds) while preserving aspect ratio. This means the top/bottom or left/right sides may be cut off.

    The "Preserve Aspect" checkbox does not do this; instead it letterboxes your image, so the whole thing is visible, but you have big ugly gaps on the sides (or top/bottom).

    In Cocoa View terms, Unity seems to provide UIViewContentModeScaleAspectFit, but I need UIViewContentModeScaleAspectFill. (Man, I do not miss Cocoa's wordy names for everything!)

    If I have to write it myself... I guess I can probably do it with the RawImage control. But it seems like such a common need, surely there's an out-of-the-box solution I'm missing?
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Got impatient. ;)

    Code (CSharp):
    1. /*
    2. * Add this component to a RawImage, to automatically adjust the
    3. * uvRect to make the image completely fill its bounds while
    4. * preserving its aspect ratio (by clipping the top/bottom or sides).
    5. */
    6. using UnityEngine;
    7. using UnityEngine.UI;
    8.  
    9. [ExecuteInEditMode]
    10.  
    11. public class RawImageAspectFill : MonoBehaviour {
    12.     RectTransform rt;
    13.     RawImage img;
    14.     Rect lastBounds;
    15.     Texture lastTexture;
    16.  
    17.     void Update() {
    18.         if (rt == null) rt = transform as RectTransform;
    19.         if (img == null) img = GetComponent<RawImage>();
    20.  
    21.         if ((rt != null && rt.rect != lastBounds) ||
    22.             (img != null && img.mainTexture != lastTexture)) UpdateUV();
    23.     }
    24.  
    25.     public void UpdateUV() {
    26.         if (rt == null || img == null) return;
    27.         lastBounds = rt.rect;
    28.         float frameAspect = lastBounds.width/lastBounds.height;
    29.  
    30.         lastTexture = img.mainTexture;
    31.         float imageAspect = (float)lastTexture.width / (float)lastTexture.height;
    32.  
    33.         if (frameAspect == imageAspect) {
    34.             img.uvRect = new Rect(0,0,1,1);
    35.         } else if (frameAspect < imageAspect) {
    36.             float w = frameAspect / imageAspect;
    37.             img.uvRect = new Rect(0.5f - w*0.5f, 0, w, 1);
    38.         } else {
    39.             float h = imageAspect / frameAspect;
    40.             img.uvRect = new Rect(0, 0.5f - h*0.5f, 1, h);
    41.         }
    42.     }
    43. }
    Seems to do what I need... but comments are welcome, of course!
     
    jGate99 and natwales like this.