1+ page.title=Optimizing Layouts for TV
2+ parent.title=Designing for TV
3+ parent.link=index.html
4+
5+ trainingnavtop=true
6+ next.title=Optimizing Navigation for TV
7+ next.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">Handle Large Bitmaps in Your Application</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>
31+ When your application is running on a television set, you should assume that the user is sitting about
32+ ten 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
34+ users with a usable and enjoyable experience, you should style and lay out your UI accordingly..
35+ </p>
36+ <p>
37+ This 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>
48+ TV 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/topics/fundamentals/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>
65+ For example, the following layout is optimized for TV:
66+ </p>
67+
68+ <img src="{@docRoot}images/training/panoramio-grid.png" />
69+
70+ <p>
71+ In 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.
73+ In this layout both GridView and Fragment have the width and height set
74+ dynamically, so they can adjust to the screen resolution. Controls are added to the left side Fragment programatically at runtime.
75+ The 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+
79+ res/layout-land-large/photogrid_tv.xml
80+ <pre>
81+ <RelativeLayout
82+ android:layout_width="fill_parent"
83+ android:layout_height="fill_parent" >
84+
85+ <fragment
86+ android:id="@+id/leftsidecontrols"
87+ android:layout_width="0dip"
88+ android:layout_marginLeft="5dip"
89+ android:layout_height="match_parent" />
90+
91+ <GridView
92+ android:id="@+id/gridview"
93+ android:layout_width="wrap_content"
94+ android:layout_height="wrap_content" />
95+
96+ </RelativeLayout>
97+ </pre>
98+
99+ <p>
100+ To set up action bar items on the left side of the screen, you can also include the <a
101+ href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarLibrary">
102+ Left navigation bar library</a> in your application to set up action items on the left side
103+ of the screen, instead of creating a custom Fragment to add controls:
104+ </p>
105+
106+ <pre>
107+ LeftNavBar bar = (LeftNavBarService.instance()).getLeftNavBar(this);
108+ </pre>
109+
110+ <p>
111+ When you have an activity in which the content scrolls vertically, always use a left navigation bar;
112+ otherwise, your users have to scroll to the top of the content to switch between the content view and
113+ the ActionBar. Look at the
114+ <a href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarDemo">
115+ Left 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>
120+ The text and controls in a TV application's UI should be easily visible and navigable from a distance.
121+ Follow 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+ <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"/>
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>
153+ The common HDTV display resolutions are 720p, 1080i, and 1080p. Design your UI for 1080p, and then
154+ allow the Android system to downscale your UI to 720p if necessary. In general, downscaling (removing pixels)
155+ does not degrade the UI (Notice that the converse is not true; you should avoid upscaling because it degrades
156+ UI quality).
157+ </p>
158+
159+ <p>
160+ To get the best scaling results for images, provide them as <a href="{@docRoot}guide/developing/tools/draw9patch.html">
161+ 9-patch image</a> elements if possible.
162+ If you provide low quality or small images in your layouts, they will appear pixelated, fuzzy, or grainy. This
163+ is not a good experience for the user. Instead, use high-quality images.
164+ </p>
165+
166+ <p>
167+ For more information on optimizing apps for large screens see <a href="{@docRoot}training/multiscreen/index.html">
168+ Designing for multiple screens</a>.
169+ </p>
170+
171+ <h2 id="HandleLargeBitmaps">Design to Handle Large Bitmaps</h2>
172+
173+ <p>
174+ The Android system has a limited amount of memory, so downloading and storing high-resolution images can often
175+ cause 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 a in-memory
190+ <a href="{@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>
0 commit comments