x


Scaling GUI buttons to be the right size no mobile

What is the right way to scale GUI buttons to be the right size on different mobile screen sizes and densities?

more ▼

asked Oct 25, 2012 at 04:19 AM

ina gravatar image

ina
4.4k 1621 1255 1301

When I create GUI that needs to be completely scalable, I don't take the classic 2D approach. It's possible to write stuff in OnGUI which completely scales based on the screen size, but I prefer a 3D approach.

This means my GUI-system is setup in 3D, with planes and colliders. That way my buttons are actually rendered, and I don't have to worry about stretching on different screens.

It's also pretty easy to dock elements to certain screen positions (top left corner, etc.) with some raycasting code.

It really depends on what you need, but if you consider taking this 3D approach, I'm happy to answer further questions you have.

Greets

Oct 25, 2012 at 06:36 AM Tim Michels
(comments are locked)
10|3000 characters needed characters left

1 answer: sort voted first

I know two approaches to scale the gui resolution independently.

One way is using GUI.matrix and multiply it with Matrix4x4.Scale(new Vector3(factor, factor, factor)). That will everything scale up or down including fonts. When I needed a gui scaling, that method didn't fit my needs so I calculated it on my own and built an android-like scale system.

In c# I wrote extension methods to convert the values (simplified code). I wrote a lot of them for int, float, rect, vectors, GuiStyle,... E.g.

@Edit: class added

public static class DisplayMetricsUtil
{
    public enum ResolutionType 
    {
        ldpi,
        mdpi,
        hdpi,
        xhdpi
    }

    private const float DEFAULT_DPI = 160.0f;

    private static bool isScreenSizeInitialized = false;

    private static Rect ScreenSize;

    public static Vector2 DpToPixel(this Vector2 vector)
    {
        return new Vector2(vector.x.DpToPixel(), vector.y.DpToPixel());
    }

    public static Vector3 DpToPixel(this Vector3 vector)
    {
        return new Vector3(vector.x.DpToPixel(), vector.y.DpToPixel(), vector.z.DpToPixel());
    }

    public static Rect DpToPixel(this Rect rect)
    {
        return new Rect(rect.x.DpToPixel(), rect.y.DpToPixel(), rect.width.DpToPixel(), rect.height.DpToPixel());
    }

    public static int DpToPixel(this int dp)
    {
        // Convert the dps to pixels
        return (int) (dp * GetScale() + 0.5f);
    }

    public static int DpToPixel(this float dp)
    {
        // Convert the dps to pixels
        return (int) (dp * GetScale() + 0.5f);
    }

    public static int PixelToDp(this int px)
    {
        // Convert the pxs to dps
        return (int) (px / GetScale() - 0.5f);
    }

    public static int PixelToDp(this float px)
    {
        // Convert the pxs to dps
        return (int) (px / GetScale() - 0.5f);
    }


    public static GUIStyle DpToPixel(this GUIStyle style)
    {
        GUIStyle stylePx = new GUIStyle(style);
        stylePx.border = stylePx.border.DpToPixel();
        stylePx.padding = stylePx.padding.DpToPixel();
        stylePx.margin = stylePx.margin.DpToPixel();
        stylePx.overflow = stylePx.overflow.DpToPixel();
        stylePx.contentOffset = stylePx.contentOffset.DpToPixel();
        stylePx.fixedWidth = stylePx.fixedWidth.DpToPixel();
        stylePx.fixedHeight = stylePx.fixedHeight.DpToPixel();
        stylePx.fontSize = stylePx.fontSize.DpToPixel();

        return stylePx;
    }


    public static RectOffset DpToPixel(this RectOffset rectOffset)
    {
        return new RectOffset(
            rectOffset.left.DpToPixel(), 
            rectOffset.right.DpToPixel(), 
            rectOffset.top.DpToPixel(), 
            rectOffset.bottom.DpToPixel());
    }


    public static Rect ScreenSizeDpUnit()
    {
        if(!isScreenSizeInitialized)
        {
            ScreenSize = new Rect(0, 0, Screen.width.PixelToDp(), Screen.height.PixelToDp());

            isScreenSizeInitialized = true;
        }

        return ScreenSize;
    }

    //e.g. switch fonts to have the correct fontsize. 
    public static ResolutionType GetResolutionType()
    {
        float scale = GetDPI() / DEFAULT_DPI;

        ResolutionType res;

        //http://developer.android.com/guide/practices/screens_support.html
        if(scale > 1.5f)
        {
            res = DisplayMetricsUtil.ResolutionType.xhdpi;
        }
        else if(scale > 1f)
        {
            res = DisplayMetricsUtil.ResolutionType.hdpi;
        }
        else if(scale > 0.75f)
        {
            res = DisplayMetricsUtil.ResolutionType.mdpi;
        }
        else
        {
            res = DisplayMetricsUtil.ResolutionType.ldpi;
        }

        return res;
    }


    private static float GetDPI()
    {
        return Screen.dpi == 0 ? DEFAULT_DPI : Screen.dpi;
    }

    private static float GetScale()
    {
        return GetDPI() / DEFAULT_DPI;
    }
}
more ▼

answered Oct 25, 2012 at 07:43 AM

robhuhn gravatar image

robhuhn
4.1k 14 15 27

Any chance that you would share more source code? I like your solution, but it's hard to figure out what to do with the few functions you outlined.

Nov 08, 2012 at 06:33 PM JustinRyder

I edited my post

Nov 09, 2012 at 09:00 AM robhuhn

how do we use extension methods in unity? Where should I copy this codescript?

May 08 at 12:09 PM mustafaguven
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x5755
x878
x420

asked: Oct 25, 2012 at 04:19 AM

Seen: 3419 times

Last Updated: May 08 at 12:09 PM