• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Optimizing Layouts for TV
2parent.title=Designing for TV
3parent.link=index.html
4
5trainingnavtop=true
6next.title=Optimizing Navigation for TV
7next.link=optimizing-navigation-tv.html
8
9@jd:body
10
11<div id="tb-wrapper">
12<div id="tb">
13
14<h2>This lesson teaches you to</h2>
15<ol>
16  <li><a href="#DesignLandscapeLayouts">Design Landscape Layouts</a></li>
17  <li><a href="#MakeTextControlsEasyToSee">Make Text and Controls Easy to See</a></li>
18  <li><a href="#DesignForLargeScreens">Design for High-Density Large Screens</a></li>
19  <li><a href="#HandleLargeBitmaps">Design to Handle Large Bitmaps</a></li>
20</ol>
21
22<h2>You should also read</h2>
23<ul>
24  <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li>
25</ul>
26
27</div>
28</div>
29
30<p>
31When your application is running on a television set, you should assume that the user is sitting about
32ten feet away from the screen. This user environment is referred to as the
33<a href="http://en.wikipedia.org/wiki/10-foot_user_interface">10-foot UI</a>. To provide your
34users with a usable and enjoyable experience, you should style and lay out your UI accordingly..
35</p>
36<p>
37This lesson shows you how to optimize layouts for TV by:
38</p>
39<ul>
40  <li>Providing appropriate layout resources for landscape mode.</li>
41  <li>Ensuring that text and controls are large enough to be visible from a distance.</li>
42  <li>Providing high resolution bitmaps and icons for HD TV screens.</li>
43</ul>
44
45<h2 id="DesignLandscapeLayouts">Design Landscape Layouts</h2>
46
47<p>
48TV screens are always in landscape orientation. Follow these tips to build landscape layouts optimized for TV screens:
49</p>
50<ul>
51  <li>Put on-screen navigational controls on the left or right side of the screen and save the
52  vertical space for content.</li>
53  <li>Create UIs that are divided into sections, by using <a href="{@docRoot}guide/components/fragments.html">Fragments</a>
54  and use view groups like {@link android.widget.GridView} instead
55  of {@link android.widget.ListView} to make better use of the
56  horizontal screen space.</li>
57  <li>Use view groups such as {@link android.widget.RelativeLayout}
58  or {@link android.widget.LinearLayout} to arrange views.
59  This allows the Android system to adjust the position of the views to the size, alignment,
60  aspect ratio, and pixel density of the TV screen.</li>
61  <li>Add sufficient margins between layout controls to avoid a cluttered UI.</li>
62</ul>
63
64<p>
65For example, the following layout is optimized for TV:
66</p>
67
68<img src="{@docRoot}images/training/panoramio-grid.png" />
69
70<p>
71In this layout, the controls are on the lefthand side. The UI is displayed within a
72{@link android.widget.GridView}, which is well-suited to landscape orientation.
73In this layout both GridView and Fragment have the width and height set
74dynamically, so they can adjust to the screen resolution. Controls are added to the left side Fragment programatically at runtime.
75The layout file for this UI is {@code res/layout-land-large/photogrid_tv.xml}.
76(This layout file is placed in {@code layout-land-large} because TVs have large screens with landscape orientation. For details refer to
77<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>.)</p>
78
79res/layout-land-large/photogrid_tv.xml
80<pre>
81&lt;RelativeLayout
82    android:layout_width="fill_parent"
83    android:layout_height="fill_parent" &gt;
84
85    &lt;fragment
86        android:id="@+id/leftsidecontrols"
87        android:layout_width="0dip"
88        android:layout_marginLeft="5dip"
89        android:layout_height="match_parent" /&gt;
90
91    &lt;GridView
92        android:id="@+id/gridview"
93        android:layout_width="wrap_content"
94        android:layout_height="wrap_content" /&gt;
95
96&lt;/RelativeLayout>
97</pre>
98
99<p>
100To set up action bar items on the left side of the screen, you can also include the <a
101href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarLibrary">
102Left navigation bar library</a> in your application to set up action items on the left side
103of the screen, instead of creating a custom Fragment to add controls:
104</p>
105
106<pre>
107LeftNavBar bar = (LeftNavBarService.instance()).getLeftNavBar(this);
108</pre>
109
110<p>
111When you have an activity in which the content scrolls vertically, always use a left navigation bar;
112otherwise, your users have to scroll to the top of the content to switch between the content view and
113the ActionBar. Look at the
114<a href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarDemo">
115Left navigation bar sample app</a> to see how to simple it is to include the left navigation bar in your app.
116</p>
117
118<h2 id="MakeTextControlsEasyToSee">Make Text and Controls Easy to See</h2>
119<p>
120The text and controls in a TV application's UI should be easily visible and navigable from a distance.
121Follow these tips to make them easier to see from a distance :
122</p>
123
124<ul>
125  <li>Break text into small chunks that users can quickly scan.</li>
126  <li>Use light text on a dark background. This style is easier to read on a TV.</li>
127  <li>Avoid lightweight fonts or fonts that have both very narrow and very broad strokes. Use simple sans-serif
128  fonts and use anti-aliasing to increase readability.</li>
129  <li>Use Android's standard font sizes:
130  <pre>
131  &lt;TextView
132        android:id="@+id/atext"
133        android:layout_width="wrap_content"
134        android:layout_height="wrap_content"
135        android:gravity="center_vertical"
136        android:singleLine="true"
137        android:textAppearance="?android:attr/textAppearanceMedium"/&gt;
138  </pre></li>
139  <li>Ensure that all your view widgets are large enough to be clearly visible to someone sitting 10 feet away
140  from the screen (this distance is greater for very large screens).  The best way to do this is to use
141  layout-relative sizing rather than absolute sizing, and density-independent pixel units instead of absolute
142  pixel units. For example, to set the width of a widget, use wrap_content instead of a pixel measurement,
143  and to set the margin for a widget, use dip instead of px values.
144  </li>
145</ul>
146<p>
147
148</p>
149
150<h2 id="DesignForLargeScreens">Design for High-Density Large Screens</h2>
151
152<p>
153The common HDTV display resolutions are 720p, 1080i, and 1080p. Design your UI for 1080p, and then
154allow the Android system to downscale your UI to 720p if necessary. In general, downscaling (removing pixels)
155does not degrade the UI (Notice that the converse is not true; you should avoid upscaling because it degrades
156UI quality).
157</p>
158
159<p>
160To get the best scaling results for images, provide them as <a href="{@docRoot}tools/help/draw9patch.html">
1619-patch image</a> elements if possible.
162If you provide low quality or small images in your layouts, they will appear pixelated, fuzzy, or grainy. This
163is not a good experience for the user. Instead, use high-quality images.
164</p>
165
166<p>
167For more information on optimizing apps for large screens see <a href="{@docRoot}training/multiscreen/index.html">
168Designing for multiple screens</a>.
169</p>
170
171<h2 id="HandleLargeBitmaps">Design to Handle Large Bitmaps</h2>
172
173<p>
174The Android system has a limited amount of memory, so downloading and storing high-resolution images can often
175cause out-of-memory errors in your app. To avoid this, follow these tips:
176</p>
177
178<ul>
179  <li>Load images only when they're displayed on the screen. For example, when displaying multiple images in
180      a {@link android.widget.GridView} or
181      {@link android.widget.Gallery}, only load an image when
182      {@link android.widget.Adapter#getView(int, View, ViewGroup) getView()}
183      is called on the View's {@link android.widget.Adapter}.
184  </li>
185  <li>Call {@link android.graphics.Bitmap#recycle()} on
186      {@link android.graphics.Bitmap} views that are no longer needed.
187  </li>
188  <li>Use {@link java.lang.ref.WeakReference} for storing references
189      to {@link android.graphics.Bitmap} objects in an in-memory
190      {@link java.util.Collection}.</li>
191  <li>If you fetch images from the network, use {@link android.os.AsyncTask}
192      to fetch them and store them on the SD card for faster access.
193      Never do network transactions on the application's UI thread.
194  </li>
195  <li>Scale down really large images to a more appropriate size as you download them; otherwise, downloading the image
196  itself may cause an "Out of Memory" exception. Here is sample code that scales down images while downloading:
197
198  <pre>
199  // Get the source image's dimensions
200  BitmapFactory.Options options = new BitmapFactory.Options();
201  // This does not download the actual image, just downloads headers.
202  options.inJustDecodeBounds = true;
203  BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
204  // The actual width of the image.
205  int srcWidth = options.outWidth;
206  // The actual height of the image.
207  int srcHeight = options.outHeight;
208
209  // Only scale if the source is bigger than the width of the destination view.
210  if(desiredWidth > srcWidth)
211    desiredWidth = srcWidth;
212
213  // Calculate the correct inSampleSize/scale value. This helps reduce memory use. It should be a power of 2.
214  int inSampleSize = 1;
215  while(srcWidth / 2 > desiredWidth){
216    srcWidth /= 2;
217    srcHeight /= 2;
218    inSampleSize *= 2;
219  }
220
221  float desiredScale = (float) desiredWidth / srcWidth;
222
223  // Decode with inSampleSize
224  options.inJustDecodeBounds = false;
225  options.inDither = false;
226  options.inSampleSize = inSampleSize;
227  options.inScaled = false;
228  // Ensures the image stays as a 32-bit ARGB_8888 image.
229  // This preserves image quality.
230  options.inPreferredConfig = Bitmap.Config.ARGB_8888;
231
232  Bitmap sampledSrcBitmap = BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
233
234  // Resize
235  Matrix matrix = new Matrix();
236  matrix.postScale(desiredScale, desiredScale);
237  Bitmap scaledBitmap = Bitmap.createBitmap(sampledSrcBitmap, 0, 0,
238      sampledSrcBitmap.getWidth(), sampledSrcBitmap.getHeight(), matrix, true);
239  sampledSrcBitmap = null;
240
241  // Save
242  FileOutputStream out = new FileOutputStream(LOCAL_PATH_TO_STORE_IMAGE);
243  scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
244  scaledBitmap = null;
245   </pre>
246  </li> </ul>