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 '12 at 04:19 AM

ina gravatar image

ina
4.2k 591 646 684

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 '12 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 '12 at 07:43 AM

robhuhn gravatar image

robhuhn
4k 5 8 18

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 '12 at 06:33 PM JustinRyder

I edited my post

Nov 09 '12 at 09:00 AM robhuhn
(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:

x5103
x735
x357

asked: Oct 25 '12 at 04:19 AM

Seen: 2361 times

Last Updated: Nov 09 '12 at 09:00 AM