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.
The simplest approach to handling multiple screen sizes in Android is to design your user interfaces such that they automatically scale for the screen size, without any size-specific code or resources. In other words, “it just works”.
This implies, though, that everything you use in your user interface can be gracefully scaled by Android and that everything will fit, even on a QVGA screen.
Here are some tips for achieving this “all in one” solution:
Don’t Think About Positions, Think About Rules
Some developers, perhaps those coming from the “drag-and-drop” school of UI development, think first and foremost about the positions of widgets. They think that they want certain widgets to be certain fixed sizes at certain fixed locations. They get frustrated with Android layout manager (containers) and may gravitate to the deprecated AbsoluteLayout as a way to design UIs they way they used to.
That rarely works well even on desktops, as can be seen by applications that do not handle window resizing very well. Similarly, it will not work on mobile devices, particularly Android, with its range of screen sizes and resolutions.
Instead of thinking about positions, think about rules. You need to teach Android the “business rules” about where widgets should be sized and placed, with Android then interpreting those rules based upon what the device’s screen actually supports in terms of resolution.
The simplest rules are the fill_parent and wrap_content values for android:layout_width and android:layout_height. Those do not specify specific sizes, but rather adapt to the space available.
The richest environment for easily specifying rules is to use RelativeLayout. While complicated on the surface, RelativeLayout does an excellent job of letting you control your layout while still adapting it to other screen sizes. For example, you can:
- Explicitly anchor widgets to the bottom or right side of the screen, rather than hoping they will wind up there courtesy of some other layout
- Control the distances between widgets that are “connected” (e.g., a label for a field should be to the left of the field) without having to rely on padding or margins
The greatest control for specifying rules is to create your own layout class. For example, suppose you are creating a series of applications that implement card games. You may want to have a layout class that knows about playing cards: how they overlap, which are face up versus face down, how big to be to handle varying number of cards, etc. While you could achieve the desired look with, say, a RelativeLayout, you may be better served implementing a PlayingCardLayout or a HandOfCardsLayout or something that is more explicitly tailored for your application. Unfortunately, creating custom layout classes is under-documented at this point in time.
Consider Physical Dimensions
Android offers a wide range of available units of measure for dimensions. The most popular has been the pixel (px), because it is easy to “wrap your head around” the concept. After all, all Android devices will have screens with such-and-so number of pixels in each direction.
However, pixels start to become troublesome as screen density changes. As the number of pixels in a given screen size increases, the pixels effectively shrink. A 32px icon on a traditional Android device might be finger-friendly, but on a high-density device (say, WVGA in a mobile phone form factor), 32px may be a bit small for use with a finger.
If you have something intrinsically scalable (e.g., a Button) where you had been specifying a size in pixels, you might consider switching to using millimeters (mm) or inches (in) as the unit of measure. 10mm is 10mm regardless of the screen resolution or the screen size. This way, you can ensure that your widget is sized to be finger-friendly, regardless of the number of pixels that might take.
Avoid “Real” Pixels
In some circumstance using millimeters for dimensions will not make sense. Then, you may wish to consider using other units of measure while still avoiding “real” pixels.
Android offers dimensions measured in density-independent pixels (dip). These map 1:1 to pixels for a 160dpi screen (e.g., a classic HVGA Android device) and scale from there. For example, on a 240dpi device (e.g., a phone-sized WVGA device), the ratio is 2:3, so 50dip = at 160dpi = 75px at 240dpi. The advantage to the user of going with dip is that the actual size of the dimension stays the same, so visibly there is no difference between 50dip at 160dpi and 50dip at 240dpi.
Android also offers dimensions measured in scaled pixels (sp). Scaled pixels, in theory, are scaled based on the user’s choice of font size (FONT_SCALE value in System.Settings).
Choose Scalable Drawables
Classic bitmaps — PNG, JPG, GIF — are not intrinsically scalable. If you are not running in “compatibility mode”, Android will not even try to scale them for you based on screen resolution and size. Whatever size of bitmap you supply is the size it will be, even if that makes the image too large or too small on some screens.
One way to address this is to try to avoid static bitmaps, using nine-patch bitmaps and XML-defined drawables (e.g., GradientDrawable) as alternatives. A nine-patch bitmap is a PNG file specially encoded to have rules indicating how that image can be stretched to take up more space. XML-defined drawables use a quasi-SVG XML language to define shapes, their strokes and fills, and so on.
The next post in the series will look at techniques for when the above techniques fail and you need to provide specific support for specific screen sizes and densities.
One question I have with reagrd to layout, which you might know the answer too.
Say there is a root linear layout and 2 linear layout nested inside (lets say the orientation of the root layout is vertical).
The bottom layout has an image of a set height but we want the other layout to fill the rest of the space.
If you leave the weight sum of the root layout to be empty (Set to whatever the default value is) and set the nested top linear layout to have a weight of 1, it'll take up the remainder of the space. Is this a small bug in the linear layout or is that expected behaviour?
I would of assumed that the default weight sum of the root layout would be 1 so setting the top layout to have weight sum of 1 would take up the entire screen pushing the bottom layout off of the screen (out of view) but it doesn't, it's as though it takes up the available space.
No, that's expected behavior, assuming the bottom linear layout has no weight. There really is no default weight sum as a fixed value — the default is whatever the sum of the actual weights are.
Cheers Mark,
I had a feeling you would know the answer – sorry for the next question, but does your book go through the Camera API?
I'm trying to perform some image processing from the camera, but struggling desperately with just getting the output.
Cheers,
Matt
hi Mark,
i am developing an camera application.
what i want is camera preview to be , landscape if application is running on tablet , portrait if application is running on mobile.
Hi,
I am trying to develop an app for which I want multiple screen support. I have read the Android article on Best practices for Multiple Screen Support. As per the article we have to follow 3 important things
1. Mention support for different screen sizes(large, medium and small) and any density in AndroidManifest.xml.
2. Place images of 3 dpi’s (120, 160, 240) in 3 folders res/ldpi, res/mdpi and res/hdpi.
3. In layout’s the dimension should be mentioned in “dip” units. Then Android will take care of the scaling on its own.
I have implemented all these points in my project. The images are picked up correctly from the appropriate folders. But the arrangements of the controls in not same.
e.g. I ran the app on three emulators
1. Resolution 240*320 dpi 120.
2. Resolution 240*320 dpi 160.
3. Resolution 240*320 dpi 240.
(All the emulator have same resolution but different density. )
The problem is the position of the controls is not same on all the three emulator. As per my understanding if the android:layout_marginLeft and android:layout_marginTop are mentioned in “dip” then this problem should not occur. As the density of the emulator increases the controls get placed more towards the right.
Is it absolutely necessary to provide layouts for different resolution and density in separate folder i.e. should i have .xml in each one of the /layout-small, /layout-medium, /layout-large, /layout-long, /layout-notlong folders so that the UI looks same on all the devices?
Am I missing some important point? Any help will be great.
Thanks.
Hey what u did for this? Can u please guide me….I have really very similer issue…. Â
Hi!
I have the same problem. I have a layout with a backgroun image (painting a menu) and I want to put on each menu option draw a transparent button. When I run this layout in several screens my transparent buttons move from the position I want.
Help please!!
did you find a solution? i have the same problem!
It is always a harrowing task for me to handle multiple screen sizes. But, thanks to the tips expounded in the article for achieving this “all in one” solution, it is made easy for us. Thanks.
i have the problem with scalable images. what is ” using nine-patch bitmaps and XML-defined drawables (e.g., GradientDrawable) as alternatives”? how to use it?
i need a sample example layout in android that works in all the screen size Any help will be appricated Id:[email protected]