| page.title=Layouts for TV |
| |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>In this document</h2> |
| <ol> |
| <li><a href="#themes">Themes</a> |
| <ol> |
| <li><a href="#leanback-theme">Leanback Theme</a></li> |
| <li><a href="#notitle-theme">NoTitleBar Theme</a></li> |
| </ol> |
| </li> |
| <li><a href="#structure">Layout Structure</a> |
| <ol> |
| <li><a href="#overscan">Overscan</a></li> |
| </ol> |
| </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> |
| </ol> |
| |
| </div> |
| </div> |
| |
| <p> |
| 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 |
| Leanback.Theme}, 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> |
| |
| <pre> |
| <activity |
| android:name="com.example.android.TvActivity" |
| android:label="@string/app_name" |
| <strong>android:theme="@style/Theme.Leanback"</strong>> |
| </pre> |
| |
| |
| <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: |
| </p> |
| |
| <pre> |
| <application> |
| ... |
| |
| <activity |
| android:name="com.example.android.TvActivity" |
| android:label="@string/app_name" |
| <strong>android:theme="@android:style/Theme.NoTitleBar"</strong>> |
| ... |
| |
| </activity> |
| </application> |
| </pre> |
| |
| |
| <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: |
| </p> |
| |
| <ul> |
| <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 |
| href="{@docRoot}guide/components/fragments.html" |
| >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> |
| <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> |
| </ul> |
| |
| |
| <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: |
| </p> |
| |
| <pre> |
| <?xml version="1.0" encoding="utf-8"?> |
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| android:id="@+id/base_layout" |
| android:layout_width="match_parent" |
| android:layout_height="match_parent" |
| android:orientation="vertical" |
| android:layout_marginTop="27dp" |
| android:layout_marginLeft="48dp" |
| android:layout_marginRight="48dp" |
| android:layout_marginBottom="27dp" > |
| </LinearLayout> |
| </pre> |
| |
| <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. |
| </p> |
| |
| |
| <h2 id="visibility">Text and Controls Visibility</h2> |
| |
| <p> |
| 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 : |
| </p> |
| |
| <ul> |
| <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: |
| <pre> |
| <TextView |
| android:id="@+id/atext" |
| android:layout_width="wrap_content" |
| android:layout_height="wrap_content" |
| android:gravity="center_vertical" |
| android:singleLine="true" |
| android:textAppearance="?android:attr/textAppearanceMedium"/> |
| </pre> |
| </li> |
| <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> |
| </ul> |
| |
| |
| <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> |
| |
| <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. |
| </p> |
| |
| <p> |
| For more information on optimizing layouts and resources for large screens see |
| <a href="{@docRoot}training/multiscreen/index.html">Designing for multiple screens</a>. |
| </p> |
| |
| |
| <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. |
| </p> |
| |
| <ul> |
| <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> |
| |
| </ul> |
| |
| <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> |
| |
| <ul> |
| <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> |
| <li>Call {@link android.graphics.Bitmap#recycle()} on |
| {@link android.graphics.Bitmap} views that are no longer needed. |
| </li> |
| <li>Use {@link java.lang.ref.WeakReference} for storing references |
| to {@link android.graphics.Bitmap} 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> |
| <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: |
| <pre> |
| // 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; |
| </pre> |
| </li> |
| </ul> |
| |