December 23, 2014

Handling Multiple Screen Sizes, Part Three

This is the first part of a several part series on handling multiple screen sizes in your Android projects. This material is adapted from a chapter in The Busy Coder’s Guide to Android Development, Version 3.0.

When designing your app, there will be times when you want to have different looks or behaviors based upon screen size or density. Android has ways for you to switch out resources or code blocks based on the environment in which your application runs. When properly used in combination with the techniques described in the preceding post, achieving screen size- and density-independence is eminently possible, at least for devices running Android 1.6 and newer.

<supports-screens>

The first step to proactively supporting screen sizes is to add the <supports-screens> element to your AndroidManifest.xml file. This specifies which screen sizes you explicitly support and which you do not. Those that you do not will be handled by the automatic “compatibility mode”.

Here is a manifest containing a <supports-screens> element:

Three of these attributes are almost self-explanatory: android:smallScreens, android:normalScreens, and android:largeScreens each take a boolean value indicating if your application explicitly supports those screens (true) or requires “compatibility mode” assistance (false).

The android:anyDensity attribute indicates whether you are taking density into account in your calculations (true) or not (false). If false, Android will pretend as though all of your dimensions (e.g., 4px) are for a normal-density (160dpi) screen. If your application is running on a screen with lower or higher density, Android will scale your dimensions accordingly. If you indicate that android:anyDensity = “true”, you are telling Android not to do that, putting the onus on you to use density-independent units, such as dip, mm, or in.

Resources and Resource Sets

The primary way to “toggle” different things based on screen size or density is to create resource sets. By creating resource sets that are specific to different device characteristics, you teach Android how to render each, with Android switching among those sets automatically.

Default Scaling

By default, Android will scale all drawable resources. Those that are intrinsically scalable, as described in the previous section, will scale nicely. Ordinary bitmaps will be scaled just using a normal scaling algorithm, which may or may not give you great results. It also may slow things down a bit. If you wish to avoid this, you will need to set up separate resource sets containing your non-scalable bitmaps.

Density-Based Sets

If you wish to have different layouts, dimensions, or the like based upon different screen densities, you can use the -ldpi, -mdpi, and -hdpi resource set labels. For example, res/values-hdpi/dimens.xml would contain dimensions used in high-density devices.

Size-Based Sets

Similarly, if you wish to have different resource sets based upon screen size, Android offers -small, -normal, and -large resource set labels. Creating res/layout-large-land/ would indicate layouts to use on large screens (e.g., WVGA) in landscape orientation.

Version-Based Sets

There may be times when earlier versions of Android get confused by newer resource set labels. To help with that, you can include a version label to your resource set, of the form -vN, where N is an API level. Hence, res/drawable-large-v4/ indicates these drawables should be used on large screens at API level 4 (Android 1.6) and newer.

Apparently, Android has had the ability to filter on version from early on, and so this technique will work going back to Android 1.5 (and, perhaps, earlier).

So, if you find that Android 1.5 emulators or devices are grabbing the wrong resource sets, consider adding -v4 to their resource set names to filter them out.

Finding Your Size

If you need to take different actions in your Java code based on screen size or density, you have a few options.

If there is something distinctive in your resource sets, you can “sniff” on that and branch accordingly in your code. For example, as will be seen in the code sample at the end of this chapter, you can have extra widgets in some layouts (e.g., res/layout-large/main.xml) — simply seeing if an extra widget exists will tell you if you are running a “large” screen or not.

You can also find out your screen size class via a Configuration object, typically obtained by an Activity via getResources().getConfiguration(). A Configuration object has a public field named screenLayout that is a bitmask indicating the type of screen the application is running on. You can test to see if your screen is small, normal, or large, or if it is “long” or not (where “long” indicates a 16:9 or similar aspect ratio, compared to 4:3). For example, here we test to see if we are running on a large screen:

There does not appear to be an easy way to find out your screen density in a similar fashion. If you absolutely need to know that, a “hack” would be to create res/values-ldpi/, res/values-mdpi/, and res/values-hdpi/ directories in your project, and add a strings.xml file to each. Put a string resource in strings.xml that is has a common name across all three resource sets and has a distinctive value (e.g., name it density, with values of ldpi, mdpi, and hdpi, respectively). Then, test the value of the string resource at runtime. This is inelegant but should work.

The next post in the series will look at ways to help you better use the emulator, and real devices, for testing these different screen sizes and densities.



  • http://soft.antonspaans.com Streets Of Boston

    About "Finding your size":
    If you need an absolute measure of your the screen's density you can use the following code:

    DisplayMetrics metrics = new DisplayMetrics();
    try {
    WindowManager winMgr = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE) ;
    winMgr.getDefaultDisplay().getMetrics(metrics);
    }
    catch (Exception e) {
    metrics.density = 1;
    }

    The value metrics.density now contains a measure of the screen's density with 160dpi density as a the 'baseline'. More info can be found here:

    http://developer.android.com/reference/android/ut

    • Mark Murphy

      Hey, thanks for the tip!

      • http://soft.antonspaans.com Streets Of Boston

        No problem. :-)

        I use this code to properly load image-thumbnails on screens with variable sizes/densities. E.g. on the Droid the thumbnails are 120×120 but on the G1 they should be 80×80 if they need to appear equally large on both phones.

  • Rene

    Users reporting issues where the scaling on 2.x devices failed finally pushed me from supporting 1.5 up to requiring 1.6 on my application.

    • http://intensedebate.com/people/droidin droidin

      As long as you realize that you are loosing at least 20% of your potential customers (according to flurry stats for my app)

  • http://mill-industries.com Eric Mill

    Both Configuration.screenLayout and DisplayMetrics.densityDpi are not present in 1.5. They were added as of 1.6, and aren't backwards compatible.

    I found this out the hard way by briefly deploying a version of my app in the Market that used DisplayMetrics.densityDpi, to hinge some logic around generating a shortcut icon bitmap of the optimal pixel dimensions for that density. I got the strangest goddamn errors – not exceptions – errors. I got runtime errors that occurred after the code was compiled down to bytecode, and I eventually fixed it by pulling that code altogether.

    I haven't tested Configuration.screenLayout personally, but it was added at the same API level, so it looks like it'd be the exact same thing. No one targeting 1.5-enabled devices should use these.

    The best solution would seem to be your strings.xml hack, which is a good solution for a silly problem.

    • Dianne

      It is relatively easy to write code that will gracefully handle running on older versions without some APIs, as described here:

      http://android-developers.blogspot.com/2009/04/ba

      You can see the use of the simpler technique, reflection, here:

      http://android-developers.blogspot.com/2010/02/se

      For more extensive APIs, you can write a wrapper class as described in the later doc that takes care of calling the API for you if it exists or otherwise doing something reasonable.

      Also you definitely want to test your app against whatever minSdkVersion you are declaring to support. Running in the simulator for that minimum platform version should be sufficient.

    • http://soft.antonspaans.com Streets Of Boston

      Hi Eric,

      But the 'metrics.density' is present (see my first comment above) and you can use this effectively. I use it in my app that is available on 1.5 as well.

  • http://timhoeck.com Tim Hoeck

    Great post Mark… explains step by step exactly what is needed. I haven't seen too many articles that detail all of these steps. Definitely looking forward to the next part to see if there is some extra emulator stuff that I am not aware of.

  • rajesh

    i tryed this line in AndroidManifest.xml

    <supports-screens
    android:largeScreens="false"
    android:normalScreens="true"
    android:smallScreens="true"
    android:anyDensity="true" />

    but i am getting the error as follow
    AndroidManifest.xml:6: ERROR No resource identifier found for attribute 'largeScreens' in package 'android'
    AndroidManifest.xml:6: ERROR No resource identifier found for attribute 'normalScreens' in package 'android'
    AndroidManifest.xml:6: ERROR No resource identifier found for attribute 'smallScreens' in package 'android'
    AndroidManifest.xml:6: ERROR No resource identifier found for attribute 'anyDensity' in package 'android'

    • alize

      Hi
      Your code version must be 1.6 or higher.

      • Yakobom

        Hi Alize,
        I’m kinda new to this, and I got the same error. Could you please explain what version number are your talking about?

        • Steven
  • https://muhammadf0628.student.ipb.ac.id cuppy

    we still need improvement.. so go go developer..

  • http://ekas0615.student.ipb.ac.id khay

    thanks for your sharing. great post! like this :p

  • Zulfiqar

    what is the explicit size in pixels when we say it
    android:largeScreens=”false”
    android:normalScreens=”true”
    android:smallScreens=”true”

  • Pingback: Developing for Multiple Screens on Android – Part 2: Implementation | MobileSnapp

  • http://www.facebook.com/chardyx Richard Limjuco Isla

    hello, do i need to create different layouts for my android app to adopt to multiple screens?

  • Pingback: Develop Multiple Screen for Android | Innovation Plus

  • http://profile.yahoo.com/K2B5OEMGQV37CKMJ265AWMH3FM Jodie

    superdry sale To be a happy person.
    coach factory outlet We will do better
    nike high heels Without you I was lonely.
    coach outlet online I believe his heart.
    air max tn Miss a friend and warm greetings.
    coach outlet store Only the smile is not tired.

  • Tharanga

    Great…! really helped…

  • kumar

    thanks for ur help , This blog solved my app problem

  • Pingback: Eden Borromeo

  • Pingback: Kevin Lefebre

  • Pingback: Aletha Uson

  • Pingback: My Homepage

  • Jyotsna Aggrawal

    Android categorizes device screens using two general properties: size and density. You should expect that your app will be installed on devices with screens that range in both size and density. As such we should include some alternative resources that optimize our app’s appearance for different screen sizes and densities

    1. There are four generalized sizes: small, normal, large, xlarge.

    2. And four generalized densities: low(ldpi), medium(mdpi), high(hdpi), extra high(xhdpi)

    To declare different layouts and bitmaps we like to use for different screens, we must place these alternative resources in separate directories, similar to how we do for different language strings.

    Also, be aware that the screens orientation (landscape or portrait) is considered a variation of screen.

    for full implementation visit here:
    http://www.mindstick.com/blog/701/Android%20Support%20for%20different%20screen%20sizes