Android’s increasing popularity is a mixed blessing for app developers. On the one hand, a wide range of devices running the Android OS opens up new and exciting development opportunities, but there’s also the increasing headache of designing an app that runs smoothly on devices with different screen sizes, pixel densities and rotation behavior. Android does support automatic resizing and rescaling, but this is no substitute for putting the effort into ensuring your app is optimized for multiple screens.
In this tutorial, I’ll introduce you to some of the core concepts of designing for different screens. I’ll show you how to easily create a dedicated landscape version of your layout, before creating a custom launcher icon that supports screens with different pixel densities.
Designing a Landscape Layout
When you create an Android project, Eclipse automatically generates a folder and XML file for defining the portrait layout. This is just the starting point: you can (and should) create multiple layout layout folders in the /res
directory. In this part of the tutorial, we’ll create a new folder and an XML layout file that’s optimized for landscape mode.
Imagine this scenario: you’ve been fine-tuning your UI and have finally got your buttons and textbox in exactly the right position:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns_android="http://schemas.android.com/apk/res/android"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
android_background="#F5FFFA" >
<Button
android_id="@+id/button1"
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_layout_alignParentLeft="true"
android_layout_alignParentTop="true"
android_text="Button 1" />
<Button
android_id="@+id/button2"
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_layout_alignParentLeft="true"
android_layout_below="@+id/button1"
android_layout_marginTop="14dp"
android:text="Button 2" />
<Button
android_id=”@+id/button3″
android_layout_width=”fill_parent”
android_layout_height=”wrap_content”
android_layout_alignParentLeft=”true”
android_layout_below=”@+id/button2″
android_layout_marginTop=”18dp”
android_text=”Button 3″ />
<Button
android_id=”@+id/button4″
android_layout_width=”fill_parent”
android_layout_height=”wrap_content”
android_layout_alignParentLeft=”true”
android_layout_below=”@+id/button3″
android_layout_marginTop=”18dp”
android_text=”Button 4″ />
<Button
android_id=”@+id/button5″
android_layout_width=”fill_parent”
android_layout_height=”wrap_content”
android_layout_alignParentLeft=”true”
android_layout_below=”@+id/button4″
android_layout_marginTop=”14dp”
android_text=”Button 5″ />
<EditText
android_id=”@+id/editText”
android_layout_width=”match_parent”
android_layout_height=”wrap_content”
android_layout_alignParentLeft=”true”
android_layout_below=”@+id/button5″
android_layout_marginTop=”15dp”
android_ems=”10″
android_hint=”Please enter your name” />
</RelativeLayout>
You’ve booted up the Android Emulator, and are confident that your work is done.
But, what if your app winds up on a device that defaults to landscape mode? Or, even more likely, a device that automatically rotates the UI whenever the device is tipped? You can test this scenario in the emulator by pressing Ctrl-F11.
Disaster! You cannot guarantee your app will be viewed exclusively in portrait mode, so you need to create an additional layout.
The first step, is create a new folder:
- Right-click on the
res
folder. - Select ‘New’ followed by ‘Folder.’
- Name your new folder
layout-land
and click ‘Ok.’
Create an Android XML file in the layout-land
folder:
- Right-click on ‘layout-land.’
- Select ‘New’ followed by ‘XML File.’
- Give the XML file the same name as the portrait version. In this example, the path of our portrait layout file is res/layout/activity_main.xml so the landscape XML layout should be res/layout-land/activity_main.xml.
Tip. At this point, Eclipse may warn you that “the destination file already exists” even though you are creating a file in a new (and completely empty!) folder. If this occurs, press ‘Next’ rather than ‘Finish,’ and type the layout-land path and filename in the subsequent dialog:
- Click ‘Finish.’
You now have two activity_main.xml layout files, and your project should be laid out like this:
Open the layout_land.xml file. You are now ready to design a second layout specifically for landscape mode. In this example, we’ll use the following layout:
<RelativeLayout xmlns_android="http://schemas.android.com/apk/res/android"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
android:background="#F5FFFA" >
<Button
android_id=”@+id/button1″
android_layout_width=”wrap_content”
android_layout_height=”wrap_content”
android:text=”Button 1″ />
<Button
android_id=”@+id/button2″
android_layout_width=”wrap_content”
android_layout_height=”wrap_content”
android_layout_marginLeft=”18dp”
android_layout_toRightOf=”@+id/button1″
android_text=”Button 2″ />
<Button
android_id=”@+id/button3″
android_layout_width=”wrap_content”
android_layout_height=”wrap_content”
android_layout_centerHorizontal=”true”
android_text=”Button 3″ />
<Button
android_id=”@+id/button4″
android_layout_width=”wrap_content”
android_layout_height=”wrap_content”
android_layout_marginLeft=”16dp”
android_layout_toRightOf=”@+id/button3″
android_text=”Button 4″ />
<Button
android_id=”@+id/button5″
android_layout_width=”wrap_content”
android_layout_height=”wrap_content”
android_layout_alignParentRight=”true”
android_layout_alignParentTop=”true”
android_text=”Button 5″ />
<EditText
android_id=”@+id/editText”
android_layout_width=”fill_parent”
android_layout_height=”wrap_content”
android_layout_alignParentLeft=”true”
android_layout_below=”@+id/button1″
android_layout_marginTop=”32dp”
android_ems=”10″
android_hint=”Please enter your name” />
</RelativeLayout>
Double-check your app displays properly in both portrait and landscape modes by running it in the Android Emulator and toggling between the different orientations.
Success!
Optimizing for Different Android Screen Densities
When developing your UI, you need to consider how your images will appear on screens with different pixel densities. The easiest and most effective solution is to create separate folders containing images targeting generalized screen densities. When a user boots up your app the Android system checks the device’s display characteristics and automatically loads images from the correct folder.
Eclipse and the ADT plugin make creating density-specific images easy. In the second part of this tutorial, I’ll demonstrate how to take advantage of the graphical layout editor’s ability to generate density-specific images and allocate them to the correct folders.
To start, ensure Eclipse’s graphical layout editor is open.
- Open the ‘Images & Media’ section of the palette.
- Drag the ‘ImageView’ icon onto the canvas.
- In the subsequent ‘Resource Chooser’ dialog, select ‘Project Resources’ followed by ‘ic_launcher’ and ‘Create new icon.’
- You’ll be presented with the following options:
- Launcher Icons — represent your application on the home screen.
- Menu Icons — represent your application when the user selects ‘Menu.’
- Action Bar Icons — represent individual items in the Action Bar.
- Tab Icons — if you have a multi-tab UI, these icons represent the individual tabs.
- Notification Icons — alert the user to a new notification
-
Ensure the ‘Launcher icon’ checkbox is ticked and do not alter the default icon name (
ic_launcher
). Click ‘Next.’ - In the ‘Configure Icon Set’ dialog, select ‘Image.’
- Select ‘Browse’ and locate the image file on your hard drive.
- At this point, you can opt to change the background or foreground colors, or select different shapes for your icon (‘none,’ ‘square’ and ‘circle.’) In this example, we’ll leave the colors alone but select the ‘Circle’ option.
-
Pay special attention to the four versions of your launcher icon on the right-hand side of the screen. These icons are your image optimized for the different screen densities:
- Low density screen icon (ldpi) Icons are 36 x 36 px
- Medium density screen icon (mdpi) Icons are 48 x 48 px
- High density screen icon (hdpi) Icons are 72 x 72 px
- Extra high density screen icon (xdpi) Icons are 96 x 96 px
- Click ‘Finish’ and Eclipse will automatically generate all four versions of your launcher icon.
- Confirm that you want to replace the existing ic_launcher files.
-
Eclipse will return to the Resource Chooser screen. Click ‘Cancel.’
Tip. If your new icon doesn’t appear automatically in the graphical layout editor, try selecting ‘Save All’ to update the graphical layout editor’s output.
-
Open the
res
folder in Eclipse’s project explorer. The new ic_launcher.png items should have been added to the fourdrawable
folders (-hpdi
,-ldpi
,-mdpi
and-xhdpi
). -
Boot up the Android Emulator, to see how your new icon appears on an Android device.
Conclusion
In this tutorial, we began to explore the core concepts of designing a UI that’s optimized for a range of devices. As a bare minimum, you should always:
- Test your app displays correctly in landscape and portrait modes
- Create a landscape-land layout if necessary
- Ensure alternate versions of your images are available for different screen densities
However, this is just scratching the surface of optimizing for different devices. If you want to learn more about this topic, you should read the Supporting Multiple Screens section of the official Android docs.