Android devices come in all shapes and sizes, so your app's layout needs to be flexible. That is, instead of defining your layout with rigid dimensions that assume a certain screen size and aspect ratio, your layout should gracefully respond to different screen sizes and orientations.
By supporting as many screens as possible, your app can be made available to the greatest number of users with different devices, using a single APK. Additionally, making your app flexible for different screen sizes ensures that your app can handle window configuration changes on the device, such as when the user enables multi-window mode.
This page shows you how to support different screen sizes with the following techniques:
- Use view dimensions that allow the layout to resize
- Create alternative UI layouts according to the screen configuration
- Provide bitmaps that can stretch with the views
But be aware that adapting to different screen sizes doesn't necessarily make your app compatible with all Android form factors. You should take additional steps to support Android Wear, TV, Auto, and Chrome OS devices.
For design guidelines for building UI for different screens, see the material guidelines for responsive UI.
Create a flexible layout
No matter what hardware profile you want to support first, you need to create a layout that is responsive to even small variations in screen size.
Use ConstraintLayout
The best way to create a responsive layout for different screen
sizes is to use ConstraintLayout
as the base layout
in your UI. ConstraintLayout
allows
you to specify the position and size for each view according to spatial
relationships with other views in the layout. This way, all the views can move
and stretch together as the screen size changes.
The easiest way to build a layout with ConstraintLayout
is to use the
Layout Editor in Android Studio. It allows you to drag new views to the layout,
attach their constraints to the parent view and other sibling views, and
edit the view's properties, all without editing any XML by hand
(see figure 1).
For more information, see Build a Responsive UI With ConstraintLayout.
Figure 1. The Layout Editor
in Android Studio showing a ConstraintLayout
file
But ConstraintLayout
won't
solve every layout scenario (especially for dynamically-loaded lists, for
which you should use RecyclerView),
but no matter what layout you use, you should always avoid hard-coding layout
sizes (see the next section).
Avoid hard-coded layout sizes
To ensure that your layout is flexible and adapts to different screen sizes,
you should use "wrap_content"
and "match_parent"
for
the width and height of most view components, instead of hard-coded sizes.
"wrap_content"
tells the view to set its size to whatever
is necessary to fit the content within that view.
"match_parent"
makes the view expand to as much as possible within
the parent view.
For example:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/lorem_ipsum" />
Although the actual layout for this view depends on other attributes in its
parent view and any sibling views, this TextView
intends to set its width to
fill all available space (match_parent
) and set its height to exactly as much
space is required by the length of the text (wrap_content
). This allows the
view to adapt to different screen sizes and different lengths of text.
Figure 2 shows how the width of the text view using "match_parent"
adjusts
as the screen width changes with device orientation.
Figure 2. A flexible text view
If you're using a LinearLayout
, you can also expand
the child views with layout weight
so that each view fills the remaining space
proportional to their weight value. However, using weights
in a nested LinearLayout
requires the system to perform multiple layout
passes to determine the size for each view, slowing your UI performance.
Fortunately, ConstraintLayout
can achieve nearly all layouts possible with
LinearLayout
without the performance impacts, so you should try converting
your layout to ConstraintLayout. Then, you can define weighted layouts with constraint chains.
Create alternative layouts
Although your layout should always respond to different screen sizes by stretching the space within and around its views, that might not provide the best user experience for every screen size. For example, the UI you designed for a phone, probably doesn't offer a good experience on a tablet. Therefore, your app should also provide alternative layout resources to optimize the UI design for certain screen sizes.
Figure 3. The same app on different screen sizes uses a different layout for each
You can provide screen-specific layouts by creating additional
res/layout/
directories—one for each
screen configuration that requires a different layout—and then append a screen
configuration qualifier to the layout
directory name (such as layout-w600dp
for screens that have 600dp of available width).
These configuration qualifiers represent the visible screen space available for your app UI. The system takes into account any system decorations (such as the navigation bar) and window configuration changes (such as when the user enables multi-window mode) when selecting the layout from your app.
To create an alternative layout in Android Studio (using version 3.0 or higher), proceed as follows:
- Open your default layout and then click Orientation for Preview
in the toolbar.
- In the drop-down list, click to create a suggested variant such as Create Landscape Variant or click Create Other.
- If you selected Create Other, the Select Resource Directory appears. Here, select a screen qualifier on the left and add it to the list of Chosen qualifiers. When you're done adding qualifiers, click OK. (See the following sections for information about screen size qualifiers.)
This creates a duplicate layout file in the appropriate layout directory so you can begin customizing the layout for that screen variant.
Use the smallest width qualifier
The "smallest width" screen size qualifier allows you to provide alternative layouts for screens that have a minimum width measured in density-independent pixels(dp or dip).
By describing the screen size as a measure of density-independent pixels, Android allows you to create layouts that are designed for very specific screen dimensions while avoiding any concerns you might have about different pixel densities.
For example,
you can create a layout named main_activity
that's optimized for handsets and
tablets by creating different versions of the file in directories as follows:
res/layout/main_activity.xml # For handsets (smaller than 600dp available width) res/layout-sw600dp/main_activity.xml # For 7” tablets (600dp wide and bigger)
The smallest width qualifier specifies the smallest of the screen's two sides, regardless of the device's current orientation, so it's a simple way to specify the overall screen size available for your layout.
Here's how other smallest width values correspond to typical screen sizes:
- 320dp: a typical phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).
- 480dp: a large phone screen ~5" (480x800 mdpi).
- 600dp: a 7” tablet (600x1024 mdpi).
- 720dp: a 10” tablet (720x1280 mdpi, 800x1280 mdpi, etc).
Figure 4 provides a more detailed view of how different screen dp widths generally correspond to different screen sizes and orientations.
Figure 4. Recommended width breakpoints to support different screen sizes
Remember that all the figures for the smallest width qualifier are density-independent pixels, because what matters is the amount of screen space available after the system accounts for pixel density (not the raw pixel resolution).
Use the available width qualifier
Instead of changing the layout based on the smallest width of the screen, you might want to change your layout based on how much width or height is currently available. For example, if you have a two-pane layout, you might want to use that whenever the screen provides at least 600dp of width, which might change depending on whether the device is in landscape or portrait orientation. In this case, you should use the "available width" qualifier as follows:
res/layout/main_activity.xml # For handsets (smaller than 600dp available width) res/layout-w600dp/main_activity.xml # For 7” tablets or any screen with 600dp # available width (possibly landscape handsets)
If the available height is a concern for you, then you can do the same using the
"available height" qualifier. For example, layout-h600dp
for
screens with at least 600dp of screen height.
Add orientation qualifiers
Although you may be able to support all size variations using only combinations of the "smallest width" and "available width" qualifiers, you might also want to change the user experience when the user switches between portrait and landscape orientations.
For that you can add the port
or land
qualifiers to your resource directory
names. Just be sure these come after the other size qualifiers. For example:
res/layout/main_activity.xml # For handsets res/layout-land/main_activity.xml # For handsets in landscape res/layout-sw600dp/main_activity.xml # For 7” tablets res/layout-sw600dp-land/main_activity.xml # For 7” tablets in landscape
For more information about all the screen configuration qualifiers, see table 2 in the guide to Providing Resources.
Modularize UI components with fragments
When designing your app for multiple screen sizes you want to make sure you aren't needlessly duplicating your UI behavior across your activities. So you should use fragments to extract your UI logic into separate components. Then, you can then combine fragments to create multi-pane layouts when running on a large screen or place in separate activities when running on a handset.
For example, a news app on a tablet might show a list of articles on the left side and a full article on the right side—selecting an article on the left updates the article view on the right. On a handset, however, these two components should appear on separate screens—selecting an article from a list changes the entire screen to show that article.
To learn more, see Building a Dynamic UI with Fragments.
Support Android 3.1 with legacy size qualifiers
If your app supports Android 3.1 (API level 12) or lower, you need to use the legacy size qualifiers in addition to the smallest/available width qualifiers from above.
From the example above, if you want a two pane layout on larger devices you need to use the "large" configuration qualifier to support version 3.1 and lower. So, to implement these layouts on those older versions, you might have the following files:
res/layout/main_activity.xml # For handsets (smaller than 640dp x 480dp) res/layout-large/main_activity.xml # For small tablets (640dp x 480dp and bigger) res/layout-xlarge/main_activity.xml # For large tablets (960dp x 720dp and bigger)
Use layout aliases
When supporting both pre- and post-3.2 Android versions you have to use both
the smallest-width and large qualifiers for your layouts. So, you would have a
file named res/layout-large/main.xml
which might be identical to
res/layout-sw600dp/main.xml
.
To avoid this duplication of the same file, you can use alias files. For example, you can define the following layouts:
res/layout/main.xml # single-pane layout res/layout/main_twopanes.xml # two-pane layout
And add these two files:
res/values-large/layout.xml
:<resources> <item name="main" type="layout">@layout/main_twopanes</item> </resources>
res/values-sw600dp/layout.xml
:<resources> <item name="main" type="layout">@layout/main_twopanes</item> </resources>
These two files have identical content, but they don’t actually define
the layout. They merely set up main
to be an alias to main_twopanes
. Since
these files have large
and sw600dp
selectors, they are
applied to large screens regardless of Android version (pre-3.2 tablets and TVs match
large
, and post-3.2 will match sw600dp
).
Create stretchable nine-patch bitmaps
If you use a bitmap as the background in a view that changes size, you will notice Android scales your images as the view grows or shrinks based on the size of the screen or content in the view. This often leads to visible blurring or other scaling artifacts. The solution is using nine-patch bitmaps, which are specially formatted PNG files that indicate which areas can and cannot be stretched.
A nine-patch bitmap is basically a standard PNG file, but with an extra 1px
border that indicates which pixels should be stretched (and with a .9.png
extension instead of just .png
). As shown in figure 5, the intersection
between the black lines on the left and top edge is the area of the bitmap that
can be stretched.
Optionally, you can also define the safe region where content should go inside the view by similarly adding lines on the right and bottom edges.
Figure 5. A nine-patch image
(button.9.png
)
When you apply a nine-patch as the background to a view, the framework stretches the image correctly to accommodate the size of the button.
For help creating a nine-patch image from a bitmap, see Create Resizable Bitmaps.
Test on all screen sizes
It's important to test your app on a variety of screen sizes so you can ensure your UI scales correctly. If you don't have access to physical devices for all the different screen sizes, you can use the Android Emulator to emulate any screen size.
If you would rather test on a physical device, but don't want to buy the devices, you can use Firebase Test Lab to access devices in a Google data center.
Declare specific screen size support
If you decide that you don't want your app to run at certain screen sizes, you can set limits for how much your screen should resize or even restrict which devices can install your app based on their screen configuration. For more information, see Declare Restricted Screen Support.