blob: b9ca7b993506788f88773671c81dab6189562bc0 [file] [log] [blame]
page.title=Layouts for TV
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<li><a href="#themes">Themes</a>
<li><a href="#leanback-theme">Leanback Theme</a></li>
<li><a href="#notitle-theme">NoTitleBar Theme</a></li>
<li><a href="#structure">Layout Structure</a>
<li><a href="#overscan">Overscan</a></li>
<li><a href="#visibility">Text and Controls Visibility</a></li>
<li><a href="#density-resources">Screen Density and Image Resources</a></li>
<li><a href="#anti-patterns">Layout Anti-Patterns</a></li>
<li><a href="#large-bitmaps">Handling Large Bitmaps</a></li>
A TV screen is typically viewed from about 10 feet away, and while it is much larger than most
other Android device displays, this type of screen does not provide the same level of precise
detail and color as a smaller device. These factors require that you create app layouts with
TV devices in mind in order to create a useful and enjoyable user experience.</p>
<p>This guide provides direction and implementation details for building effective layouts inN
TV apps.</p>
<h2 id="themes">Themes</h2>
<p>Android <a href="{@docRoot}guide/topics/ui/themes.html">Themes</a> can provide a basis for
layouts in your TV apps. You should use a theme to modify the display of your app activities
that are meant to run on a TV device. This section explains which themes you should use.</p>
<h3 id="leanback-theme">Leanback Theme</h3>
<p>The Leanback library provides a standard theme for TV activities, called {@code
Theme.Leanback}, which establishes a consistent visual style for TV apps. Use of this theme is
recommended for most apps. This theme is recommended for any TV app that uses the Leanback
library classes. The following code sample shows how to apply this theme to a given
activity within an app:</p>
<h3 id="notitle-theme">NoTitleBar Theme</h3>
<p>The title bar is a standard user interface element for Android apps on phones and tablets,
but it is not appropriate for TV apps. If you are not using the Leanback library classes,
you should apply this theme to your TV activities. The following code example from a TV app
manifest demonstrates how to apply this theme to remove the display of a title bar:
<h2 id="structure">Layout Structure</h2>
<p>Layouts for TV devices should follow some basic guidelines to ensure they are usable and
effective on large screens. Follow these tips to build landscape layouts optimized for TV screens:
<li>Build layouts with a landscape orientation. TV screens always display in landscape.</li>
<li>Put on-screen navigation controls on the left or right side of the screen and save the
vertical space for content.</li>
<li>Create UIs that are divided into sections, using <a
>Fragments</a>, and use view groups like {@link android.widget.GridView} instead of {@link
android.widget.ListView} to make better use of the horizontal screen space.
<li>Use view groups such as {@link android.widget.RelativeLayout} or {@link
android.widget.LinearLayout} to arrange views. This approach allows the system to adjust the
position of the views to the size, alignment, aspect ratio, and pixel density of a TV screen.</li>
<li>Add sufficient margins between layout controls to avoid a cluttered UI.</li>
<h3 id="overscan">Overscan</h3>
<p>Layouts for TV have some unique requirements due to the evolution of TV standards and the
desire to always present a full screen picture to viewers. For this reason, TV devices may
clip the outside edge of an app layout in order to ensure that the entire display is filled.
This behavior is generally referred to as Overscan.</p>
<p>In order to account for the impact of overscan and make sure that all the user interface
elements you place in a layout are actually shown on screen, you should incorporate a 10% margin
on all sides of your layout. This translates into a 27dp margin on the left and right edges and
a 48dp margin on the top and bottom of your base layouts for activities. The following
example layout demonstrates how to set these margins in the root layout for a TV app:
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;LinearLayout xmlns:android=""
android:layout_marginBottom="27dp" &gt;
<p class="caution">
<strong>Caution:</strong> Do not apply overscan margins to your layout if you are using the
Leanback Support Library {@code BrowseFragment} or related widgets, as those layouts already
incorporate overscan-safe margins.
<h2 id="visibility">Text and Controls Visibility</h2>
The text and controls in a TV app layout should be easily visible and navigable from a distance.
Follow these tips to make them easier to see from a distance :
<li>Break text into small chunks that users can quickly scan.</li>
<li>Use light text on a dark background. This style is easier to read on a TV.</li>
<li>Avoid lightweight fonts or fonts that have both very narrow and very broad strokes.
Use simple sans-serif fonts and anti-aliasing to increase readability.</li>
<li>Use Android's standard font sizes:
<li>Ensure that all your view widgets are large enough to be clearly visible to someone
sitting 10 feet away from the screen (this distance is greater for very large screens). The
best way to do this is to use layout-relative sizing rather than absolute sizing, and
density-independent pixel units instead of absolute pixel units. For example, to set the
width of a widget, use wrap_content instead of a pixel measurement, and to set the margin
for a widget, use dip instead of px values.</li>
<h2 id="density-resources">Screen Density and Image Resources</h2>
<p>The common high-definition TV display resolutions are 720p, 1080i, and 1080p.
Your TV layout should target a screen size of 1920 x 1080 pixels, and then allow the Android
system to downscale your layout elements to 720p if necessary. In general, downscaling
(removing pixels) does not degrade your layout presentation quality. However, upscaling can
cause display artifacts that degrade the quality of your layout and have a negative impact on
the user experience of your app.</p>
To get the best scaling results for images, provide them as
<a href="{@docRoot}tools/help/draw9patch.html">9-patch image</a> elements if possible. If you
provide low quality or small images in your layouts, they will appear pixelated, fuzzy, or
grainy. This is not a good experience for the user. Instead, use high-quality images.
For more information on optimizing layouts and resources for large screens see
<a href="{@docRoot}training/multiscreen/index.html">Designing for multiple screens</a>.
<h2 id="anti-patterns">Layout Anti-Patterns</h2>
<p>There are a few approaches to building layouts for TV that you should avoid because they do not
work well and lead to bad user experiences. Here are some user interface approaches you
should specifically <em>not</em> use when developing a layout for TV.
<li><strong>Re-using phone or tablet layouts</strong> - Do not reuse layouts from a phone or
tablet app without modification. Layouts built for other Android device form factors are not
well suited for TV devices and should be simplified for operation on a TV.</li>
<li><strong>ActionBar</strong> - While this user interface convention is recommended for use
on phones and tablets, it is not appropriate for a TV interface. In particular, using an
action bar options menu (or any pull-down menu for that matter) is strongly discouraged, due
to the difficulty in navigating such a menu with a remote control.</li>
<li><strong>ViewPager</strong> - Sliding between screens can work great on a phone or tablet,
but don't try this on a TV!</li>
<p>For more information on designing layouts that are appropriate to TV, see the
<a href="{@docRoot}design/tv/index.html">TV Design</a> guide.</p>
<h2 id="large-bitmaps">Handling Large Bitmaps</h2>
<p>TV devices, like any other Android device, have a limited amount of memory. If you build your
app layout with very high-resolution images or use many high-resolution images in the operation
of your app, it can quickly run into memory limits and cause out of memory errors.
To avoid these types of problems, follow these tips:</p>
<li>Load images only when they're displayed on the screen. For example, when displaying multiple images in
a {@link android.widget.GridView} or
{@link android.widget.Gallery}, only load an image when
{@link android.widget.Adapter#getView(int, View, ViewGroup) getView()}
is called on the View's {@link android.widget.Adapter}.
<li>Call {@link} on
{@link} views that are no longer needed.
<li>Use {@link java.lang.ref.WeakReference} for storing references
to {@link} objects in an in-memory
{@link java.util.Collection}.</li>
<li>If you fetch images from the network, use {@link android.os.AsyncTask}
to fetch and store them on the device for faster access.
Never do network transactions on the application's UI thread.
<li>Scale down large images to a more appropriate size as you download them;
otherwise, downloading the image itself may cause an out of memory exception.
The following sample code demonstrates how to scale down images while downloading:
// Get the source image's dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
// This does not download the actual image, just downloads headers.
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
// The actual width of the image.
int srcWidth = options.outWidth;
// The actual height of the image.
int srcHeight = options.outHeight;
// Only scale if the source is bigger than the width of the destination view.
if(desiredWidth > srcWidth)
desiredWidth = srcWidth;
// Calculate the correct inSampleSize/scale value. This approach helps reduce
// memory use. This value should be a power of 2.
int inSampleSize = 1;
while(srcWidth / 2 > desiredWidth){
srcWidth /= 2;
srcHeight /= 2;
inSampleSize *= 2;
float desiredScale = (float) desiredWidth / srcWidth;
// Decode with inSampleSize
options.inJustDecodeBounds = false;
options.inDither = false;
options.inSampleSize = inSampleSize;
options.inScaled = false;
// Ensures the image stays as a 32-bit ARGB_8888 image.
// This preserves image quality.
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap sampledSrcBitmap = BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
// Resize
Matrix matrix = new Matrix();
matrix.postScale(desiredScale, desiredScale);
Bitmap scaledBitmap = Bitmap.createBitmap(sampledSrcBitmap, 0, 0,
sampledSrcBitmap.getWidth(), sampledSrcBitmap.getHeight(), matrix, true);
sampledSrcBitmap = null;
// Save
FileOutputStream out = new FileOutputStream(LOCAL_PATH_TO_STORE_IMAGE);
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
scaledBitmap = null;