- Home /
Scaling RectTransform to fit screen size in code
I am trying to scale a UI Image with Children (with a fixed x/y ratio) to best fit the screen. My code works fine when using the editors "Free Aspect" mode and scales just as expected when I change the screen size. When I use one of the preset screen sizes (in this case it's "1820x720 Portrait (720x1820)") my scaling no longer works.
Here is my code (this method is executed 3 times every second):
public IEnumerator IScale()
{
yield return new WaitForEndOfFrame();
trueSize.x = rt.sizeDelta.x * rt.localScale.x;
trueSize.y = rt.sizeDelta.y * rt.localScale.y;
resolution.x = Screen.width;
resolution.y = Screen.height;
trueSize.x = sizeX * rt.localScale.x;
trueSize.y = sizeY * rt.localScale.y;
print("Resolution: " + resolution.x + " | " + resolution.y + " True Size: " + trueSize.x + " | " + trueSize.y);
float x = 0;
float y = 0;
landscape = (resolution.x >= resolution.y);
if (landscape)
{
space.y = resolution.y * 0.5f;
space.x = resolution.x * 0.75f;
y = space.y;
if (trueSize.y > space.y)
{
y = space.y;
}
if (trueSize.x > resolution.x)
{
x = space.x;
}
y /= sizeY;
x = y;
}
else
{
space.x = resolution.x * 0.9f;
space.y = resolution.y * 0.5f;
x = space.x;
if (trueSize.y > space.y)
{
y = space.y;
}
if (trueSize.x > space.x)
{
x = space.x;
}
x /= sizeX;
y = x;
}
rt.localScale = new Vector2(x, y);
}
The print that I added:
print("Resolution: " + resolution.x + " | " + resolution.y + " True Size: " + trueSize.x + " | " + trueSize.y);
Prints exactly the same as when the scaling is working in the Free Aspect mode with trueSize always being smaller than the resolution.
I have read other posts online which suggested waiting for the end of the frame to read the size of the rectTransform, but that hasn't worked for me. It is especially confusing to me that everything is working fine in the Free Aspect mode.
Any help would be highly apreciated!
Thanks
Answer by Santifocus · Sep 22, 2019 at 01:58 PM
If you are working with a RectTransform and know exactly the size you want it to take then maybe this will help you
private void ScaleMyRect(RectTransform myRect)
{
//If you want the middle of the rect be somewhere else then the middle of the screen change it here (0 ... 1, 0 ... 1)
Vector2 rectMiddle = new Vector2(0.5f, 0.5f);
float horizontalSize = 0.5f; //50% of horizontal screen used
float verticalSize = 0.75f; //75% of vertical screen used
myRect.sizeDelta = Vector2.zero; //Dont want any delta sizes, because that would defeat the point of anchors
myRect.anchoredPosition = Vector2.zero; //And the position is set by the anchors aswell so we set the offset to 0
myRect.anchorMin = new Vector2(rectMiddle.x - horizontalSize / 2,
rectMiddle.y - verticalSize / 2);
myRect.anchorMax = new Vector2(rectMiddle.x + horizontalSize / 2,
rectMiddle.y + verticalSize / 2);
}
Yes it would depending on the input on horizontal / vertical -size. Would this work for you then?
private enum Ratio$$anonymous$$eeper { Horizontal, Vertical }
private void Scale$$anonymous$$yRect(Image myImage, Ratio$$anonymous$$eeper axis$$anonymous$$eeper, float size)
{
if(!myImage.sprite)
{
Debug.LogError("The given Image did not have a sprite from which the ratio could be calcultated.");
return;
}
//If you want the middle of the rect be somewhere else then the middle of the screen change it here (0 ... 1, 0 ... 1)
Vector2 rect$$anonymous$$iddle = new Vector2(0.5f, 0.5f);
float verticalSize = 0;
float horizontalSize = 0;
if (axis$$anonymous$$eeper == Ratio$$anonymous$$eeper.Horizontal)
{
//get the ratio from width to height by dividing h / w
float ratio = myImage.sprite.texture.height / (float)myImage.sprite.texture.width;
horizontalSize = size;
//multiply the horizontal size with the ratio
verticalSize = horizontalSize * ratio * (Screen.width / (float)Screen.height);
}
else //axis$$anonymous$$eeper == Ratio$$anonymous$$eeper.Vertical
{
//get the ratio from height to width by dividing w / h
float ratio = myImage.sprite.texture.width / (float)myImage.sprite.texture.height;
verticalSize = size;
//multiply the verticalSize size with the ratio
horizontalSize = verticalSize * ratio * (Screen.height / (float)Screen.width);
}
myImage.rectTransform.sizeDelta = Vector2.zero; //Dont want any delta sizes, because that would defeat the point of anchors
myImage.rectTransform.anchoredPosition = Vector2.zero; //And the position is set by the anchors aswell so we set the offset to 0
myImage.rectTransform.anchor$$anonymous$$in = new Vector2(rect$$anonymous$$iddle.x - horizontalSize / 2,
rect$$anonymous$$iddle.y - verticalSize / 2);
myImage.rectTransform.anchor$$anonymous$$ax = new Vector2(rect$$anonymous$$iddle.x + horizontalSize / 2,
rect$$anonymous$$iddle.y + verticalSize / 2);
}
Your method makes perfect sense, the problem is that 200px*300px is not the same as 20% of the screen * 30% of the screen, which is basically what the anchors are doing (or at least if I understood correctly)