Android: Support multiple screen sizes by scaling dimensions

Islam Khaled
5 min readApr 17, 2022

--

Supporting multiple screen sizes
The nightmare you definitely have faced before as an Android engineer, also the android team gives it a great attention for a better user experience.

By Navigating through the android developer website, stack overflow, and other resources and articles you will find different approaches to achieve that. One of them is to create alternative layout, and from here we start.

Alternative Resources
This approach depends on providing alternative layouts that fit the sizes of the different devices you target using smallest-width(sw) qualifier.

In the same way, you can save your effort and provide alternative dimensions, not layouts. But Wait!!!

Once you start providing alternative dimensions, you will face some challenges:

1- There is a wide variation in android devices’ sizes. How can you provide alternative dimensions to fit all these devices?!

2- How to scale your dimensions?! In most cases, you have a UI design with some dimensions that fit the device used in the design, but you need to scale these dimensions to fit all devices.

3- For every new dimension you use in your app you need to override it in all alternative dimensions’ resources.

Xdimen is the solution.

What’s Xdimen?
It’s a Gradle plugin that generates alternative dimensions for you.

Find it in Github.

After adding the plugin to your android module as mentioned in the repo you will need to configure it

xdimen {
designWidth.set(411) // required
designDpi.set(mdpi())
...
}

Here we solve the second-mentioned problem How to scale your dimensions? All you need is to specify the size of the device used in the design by set two properties:

  • designWidth : The width of the screen in the UI design.
  • designDpi : The UI design density (dot-per-inch).

designWidth is required and intended to be in unit dp, but if your design is in pixel you can use it and set designDpi to MDPI as in MDPI 1 px = 1 dp.

Because MDPI density (160 dpi) is the baseline, we need to calculate the relativeDesignWidth (width relative to main density MDPI) by this equation

relativeDesignWidth = designWidth * 160 / designDpi

The next step is to calculate the scaling factor for every device you target by

scalingFactor = targetDeviceWidth / relativeDesignWidth

Confused !!
Confused!!

Confused!! Let’s explain it with a numerical example:

Assume that we have a design with a screen width 600dp and screen density HDPI (240 dpi) and we need to target some devices with width 320dp, 389dp, and 450dp.

1- Calculate the relativeDesignWidth

relativeDesignWidth = 600 * 160 / 240 = 400

2- Calculate the scaling factor

320dp -> scalingFactor = 320/400 = 0.8
389dp -> scalingFactor = 389/400 = 0.9725
450dp -> scalingFactor = 450/400 = 1.125

3- Generate an alternative dimensions resource for every device you target by multiplying every dimension by the scalingFactor.

That’s what Xdimen does under the hood to make you just set designWidth and designDpi, and it will do this work instead of you.

Another configuration property:

xdimen {
targetDevicesWidth.set(phonePortrait)
...
}

targetDevicesWidth List of widths (in dp) of your target devices. For every width in this list, an alternative resource will be generated with scaled dimensions.

e.g. if targetDevicesWidth.set(setOf(350, 400)), Xdimen will generate these files


-> values/xdimen.xml # Devices with screen-width less than 350dp.
-> values-w350dp/xdimen.xml # 350dp <= screen-width < 400dp
-> values-w400dp/xdimen.xml # screen-width >= 400dp

Using width(-w…dp) qualifier instead of smallest-width(-sw…dp) will be explained later.

The great thing with this property is it can solve the first mentioned problem: There is a wide variation in android devices’ sizes. How can you provide alternative dimensions to fit all these devices?! By using the predefined lists.

Xdimen provides predefined lists of the common android devices’ widths categorized by type (phone/tablet) and orientation (portrait/landscape):

  • phonePortrait: common phones in portrait orientation.
  • phoneLandscape: common phones in landscape orientation.
  • tabletPortrait: common tablets in portrait orientation.
  • tabletLandscape: common tablets in landscape orientation.
  • devicesInPortrait: common phones and tablets in portrait.
  • devicesInLandscape: common phones and tablets in the landscape.

You can combine multiple devices list, but I recommend not to target both portrait and landscape unless you provide a custom layout for landscape or using Pane Layout.

These lists were collected from many sources: Wikipedia, ScreenSize, Pixensity, and others.

Now we have solved the first two problems, but what about the last one: For every new dimension you use in your app you need to override it in all alternative dimensions' resources.

xdimen {
dimensRange {
minDimen.set(-10)
maxDimen.set(500)
step.set(0.5)
}
fontsRange {
minDimen.set(10)
maxDimen.set(60)
step.set(1.0)
}
...
}

Set your range of dimensions and fonts you want to generate and scale:

  • minDimen: the minimum dimension to generate.
  • maxDimen: the maximum dimension to generate.
  • step: the step between two generated dimensions.

e.g. if you have the following configs

dimensRange {
minDimen.set(-5)
maxDimen.set(5)
step.set(2.5)
}

This means these dimensions will be generated:

-5   -> neg_x5dp        # neg_ prefix for negative dimensions
-2.5 -> neg_x2_5dp # for fraction digits: _fraction
2.5 -> x2_5dp
5 -> x5dp

Fonts are generated with the same names, but instead of dp it’s sp.

Almost Done!

Just run this command $ gradle :{prjectName}:generateXdimen to generate your alternative resources and have a happy coding.

Replace {prjectName} with the name of the android module which xdimen plugin applied in.

sample of generated alternative resources.

Things are done, you can skip this section if you are not interested.

You may ask why we used the width(-w…dp) qualifier however the smallest-width(-sw…dp) qualifier is the used one in the approach we follow create-alternative-layouts?

That’s because the smallest width of a window is the smallest width in the case of portrait and landscape which is always the width of portrait, and this way you can’t target landscape orientation, but the width qualifier solves it.

Find more info here

Done!

Xdimen plugin repo

IslamKhSh/Xdimen: Easily support android multiple screen sizes (github.com)

Feel free to enhance and contribute.

--

--