Home | History | Annotate | Download | only in multiscreen
      1 page.title=Supporting Different Screen Sizes
      2 parent.title=Designing for Multiple Screens
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 next.title=Supporting Different Screen Densities
      7 next.link=screendensities.html
      8 
      9 @jd:body
     10 
     11 
     12 <!-- This is the training bar -->
     13 <div id="tb-wrapper"> 
     14 <div id="tb"> 
     15 
     16 <h2>This lesson teaches you to</h2>
     17 <ol>
     18   <li><a href="#TaskUseWrapMatchPar">Use "wrap_content" and "match_parent"</a></li>
     19   <li><a href="#TaskUseRelativeLayout">Use RelativeLayout</a></li>
     20   <li><a href="#TaskUseSizeQuali">Use Size Qualifiers</a></li>
     21   <li><a href="#TaskUseSWQuali">Use the Smallest-width Qualifier</a></li>
     22   <li><a href="#TaskUseAliasFilters">Use Layout Aliases</a></li>
     23   <li><a href="#TaskUseOriQuali">Use Orientation Qualifiers</a></li>
     24   <li><a href="#TaskUse9Patch">Use Nine-patch Bitmaps</a></li>
     25 </ol>
     26 
     27 <h2>You should also read</h2>
     28 
     29 <ul>
     30   <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li>
     31 </ul>
     32 
     33 <h2>Try it out</h2> 
     34  
     35 <div class="download-box"> 
     36 <a href="http://developer.android.com/shareables/training/NewsReader.zip" class="button">Download
     37   the sample app</a>
     38 <p class="filename">NewsReader.zip</p> 
     39 </div> 
     40  
     41 </div> 
     42 </div> 
     43 
     44 <p>This lesson shows you how to support different screen sizes by:</p>
     45 <ul> 
     46   <li>Ensuring your layout can be adequately resized to fit the screen</li> 
     47   <li>Providing appropriate UI layout according to screen configuration</li> 
     48   <li>Ensuring the correct layout is applied to the correct screen</li>
     49   <li>Providing bitmaps that scale correctly</li> 
     50 </ul> 
     51 
     52 
     53 <h2 id="TaskUseWrapMatchPar">Use "wrap_content" and "match_parent"</h2> 
     54 
     55 <p>To ensure that your layout is flexible and adapts to different screen sizes,
     56 you should use <code>"wrap_content"</code> and <code>"match_parent"</code> for the width
     57 and height of some view components. If you use <code>"wrap_content"</code>, the width
     58 or height of the view is set to the minimum size necessary to fit the content
     59 within that view, while <code>"match_parent"</code> (also known as
     60 <code>"fill_parent"</code> before API level 8) makes the component expand to match the size of its
     61 parent view.</p>
     62 
     63 <p>By using the <code>"wrap_content"</code> and <code>"match_parent"</code> size values instead of
     64 hard-coded sizes, your views either use only the space required for that
     65 view or expand to fill the available space, respectively. For example:</p>
     66 
     67 {@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all}
     68 
     69 <p>Notice how the sample uses <code>"wrap_content"</code> and <code>"match_parent"</code>
     70 for component sizes rather than specific dimensions. This allows the layout
     71 to adapt correctly to different screen sizes and orientations.</p>
     72 
     73 <p>For example, this is what this layout looks like in portrait and landscape
     74 mode. Notice that the sizes of the components adapt automatically to the
     75 width and height:</p>
     76 
     77 <img src="{@docRoot}images/training/layout-hvga.png" />
     78 <p class="img-caption"><strong>Figure 1.</strong> The News Reader sample app in portrait (left)
     79 and landscape (right).</p>
     80 
     81 
     82 <h2 id="TaskUseRelativeLayout">Use RelativeLayout</h2> 
     83 
     84 <p>You can construct fairly complex layouts using nested instances of {@link
     85 android.widget.LinearLayout} and
     86 combinations of <code>"wrap_content"</code> and <code>"match_parent"</code> sizes. 
     87 However, {@link android.widget.LinearLayout} does not allow you to precisely control the
     88 spacial relationships of child views; views in a {@link android.widget.LinearLayout} simply line up
     89 side-by-side. If you need child views to be oriented in variations other than a straight line, a
     90 better solution is often to use a {@link android.widget.RelativeLayout}, which allows
     91 you to specify your layout in terms of the spacial relationships between
     92 components. For instance, you can align one child view on the left side and another view on
     93 the right side of the screen.</p>
     94 
     95 <p>For example:</p>
     96 
     97 <pre>
     98 &lt;?xml version="1.0" encoding="utf-8"?&gt;
     99 &lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    100     android:layout_width="match_parent"
    101     android:layout_height="match_parent"&gt;
    102     &lt;TextView
    103         android:id="&#64;+id/label"
    104         android:layout_width="match_parent"
    105         android:layout_height="wrap_content"
    106         android:text="Type here:"/&gt;
    107     &lt;EditText
    108         android:id="&#64;+id/entry"
    109         android:layout_width="match_parent"
    110         android:layout_height="wrap_content"
    111         android:layout_below="&#64;id/label"/&gt;
    112     &lt;Button
    113         android:id="&#64;+id/ok"
    114         android:layout_width="wrap_content"
    115         android:layout_height="wrap_content"
    116         android:layout_below="&#64;id/entry"
    117         android:layout_alignParentRight="true"
    118         android:layout_marginLeft="10dp"
    119         android:text="OK" /&gt;
    120     &lt;Button
    121         android:layout_width="wrap_content"
    122         android:layout_height="wrap_content"
    123         android:layout_toLeftOf="&#64;id/ok"
    124         android:layout_alignTop="&#64;id/ok"
    125         android:text="Cancel" /&gt;
    126 &lt;/RelativeLayout&gt;
    127 </pre>
    128 
    129 <p>Figure 2 shows how this layout appears on a QVGA screen.</p>
    130 
    131 <img src="{@docRoot}images/training/relativelayout1.png" />
    132 <p class="img-caption"><strong>Figure 2.</strong> Screenshot on a QVGA screen (small screen).</p>
    133 
    134 <p>Figure 3 shows how it appears on a larger screen.</p>
    135 
    136 <img src="{@docRoot}images/training/relativelayout2.png" />
    137 <p class="img-caption"><strong>Figure 3.</strong> Screenshot on a WSVGA screen (large screen).</p>
    138 
    139 <p>Notice that although the size of the components changed, their
    140 spatial relationships are preserved as specified by the {@link
    141 android.widget.RelativeLayout.LayoutParams}.</p>
    142 
    143  
    144 <h2 id="TaskUseSizeQuali">Use Size Qualifiers</h2> 
    145 
    146 <p>There's only so much mileage you can get from a flexible layout or relative layout
    147 like the one in the previous sections. While those layouts adapt to
    148 different screens by stretching the space within and around components, they
    149 may not provide the best user experience for each screen size. Therefore, your
    150 application should not only implement flexible layouts, but should also provide
    151 several alternative layouts to target different screen configurations. You do
    152 so by using <a href="http://developer.android.com/guide/practices/screens_support.html#qualifiers">configuration qualifiers</a>, which allows the runtime 
    153 to automatically select the appropriate resource based on the current devices
    154 configuration (such as a different layout design for different screen sizes).</p>
    155 
    156 <p>For example, many applications implement the "two pane" pattern for large
    157 screens (the app might show a list of items on one pane and the content on
    158 another pane). Tablets and TVs are large enough for both panes to fit
    159 simultaneously on screen, but phone screens have to show them separately. So,
    160 to implement these layouts, you could have the following files:</p>
    161 
    162 <ul>
    163   <li><code>res/layout/main.xml</code>, single-pane (default) layout:
    164 
    165 {@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all}
    166 </li>
    167   <li><code>res/layout-large/main.xml</code>, two-pane layout:
    168 
    169 {@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all}
    170 </li>
    171 </ul>
    172 
    173 <p>Notice the <code>large</code> qualifier in the directory name of the second layout. This layout
    174 will be selected on devices with screens classified as large (for example, 7" tablets and above). The
    175 other layout (without qualifiers) will be selected for smaller devices.</p>
    176 
    177 
    178 <h2 id="TaskUseSWQuali">Use the Smallest-width Qualifier</h2>
    179 
    180 <p>One of the difficulties developers had in pre-3.2 Android devices was the
    181 "large" screen size bin, which encompasses the Dell Streak, the original Galaxy
    182 Tab, and 7" tablets in general. However, many applications may want to show
    183 different layouts for different devices in this category (such as for 5" and 7" devices), even
    184 though they are all considered to be "large" screens. That's why Android introduced the
    185 "Smallest-width" qualifier (amongst others) in Android 3.2.</p>
    186 
    187 <p>The Smallest-width qualifier allows you to target screens that have a certain minimum
    188 width given in dp. For example, the typical 7" tablet has a minimum width of
    189 600 dp, so if you want your UI to have two panes on those screens (but a single
    190 list on smaller screens), you can use the same two layouts from the previous section for single
    191 and two-pane layouts, but instead of the <code>large</code> size qualifier, use
    192 <code>sw600dp</code> to indicate the two-pane layout is for screens on which the smallest-width
    193 is 600 dp:</p>
    194 
    195 <ul>
    196   <li><code>res/layout/main.xml</code>, single-pane (default) layout:
    197 
    198 {@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all}
    199 </li>
    200   <li><code>res/layout-sw600dp/main.xml</code>, two-pane layout:
    201 
    202 {@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all}
    203 </li>
    204 </ul>
    205 
    206 <p>This means that devices whose smallest width is greater than or equal to
    207 600dp will select the <code>layout-sw600dp/main.xml</code> (two-pane) layout,
    208 while smaller screens will select the <code>layout/main.xml</code> (single-pane)
    209 layout.</p>
    210 
    211 <p>However, this won't work well on pre-3.2 devices, because they don't
    212 recognize <code>sw600dp</code> as a size qualifier, so you still have to use the <code>large</code>
    213 qualifier as well. So, you should have a file named 
    214 <code>res/layout-large/main.xml</code>
    215 which is identical to <code>res/layout-sw600dp/main.xml</code>. In the next section
    216 you'll see a technique that allows you to avoid duplicating the layout files this way.</p>
    217 
    218 
    219 <h2 id="TaskUseAliasFilters">Use Layout Aliases</h2> 
    220 
    221 <p>The smallest-width qualifier is available only on Android 3.2 and above.
    222 Therefore, you should also still use the abstract size bins (small, normal,
    223 large and xlarge) to be compatible with earlier versions. For example, if you
    224 want to design your UI so that it shows a single-pane UI on phones but a
    225 multi-pane UI on 7" tablets, TVs and other large devices, you'd have to supply these
    226 files:</p>
    227 
    228 <p><ul>
    229 <li><code>res/layout/main.xml:</code> single-pane layout</li>
    230 <li><code>res/layout-large:</code> multi-pane layout</li>
    231 <li><code>res/layout-sw600dp:</code> multi-pane layout</li>
    232 </ul></p>
    233 
    234 <p>The last two files are identical, because one of them will be matched by
    235 Android 3.2 devices, and the other one is for the benefit of tablets and TVs with
    236 earlier versions of Android.</p>
    237 
    238 <p>To avoid this duplication of the same file for tablets and TVs (and the maintenance
    239 headache resulting from it), you can use alias files. For example, you can define the following
    240 layouts:</p>
    241 
    242 <ul>
    243 <li><code>res/layout/main.xml</code>, single-pane layout</li>
    244 <li><code>res/layout/main_twopanes.xml</code>, two-pane layout</li>
    245 </ul>
    246 
    247 <p>And add these two files:</p>
    248 
    249 <p><ul>
    250 <li><code>res/values-large/layout.xml</code>:
    251 <pre>
    252 &lt;resources>
    253     &lt;item name="main" type="layout">&#64;layout/main_twopanes&lt;/item>
    254 &lt;/resources>
    255 </pre>
    256 </li>
    257 
    258 <li><code>res/values-sw600dp/layout.xml</code>:
    259 <pre>
    260 &lt;resources>
    261     &lt;item name="main" type="layout">&#64;layout/main_twopanes&lt;/item>
    262 &lt;/resources>
    263 </pre>
    264 
    265 </li>
    266 </ul></p>
    267 
    268 <p>These latter two files have identical content, but they dont actually define
    269 the layout. They merely set up {@code main} to be an alias to {@code main_twopanes}. Since
    270 these files have <code>large</code> and <code>sw600dp</code> selectors, they are
    271 applied to tablets and TVs regardless of Android version (pre-3.2 tablets and TVs match
    272 {@code large}, and post-3.2 will match <code>sw600dp</code>).</p>
    273 
    274 
    275 <h2 id="TaskUseOriQuali">Use Orientation Qualifiers</h2> 
    276 
    277 <p>Some layouts work well in both landscape and portrait orientations, but most of them can
    278 benefit from adjustments. In the News Reader sample app, here is how the layout
    279 behaves in each screen size and orientation:</p>
    280 
    281 <p><ul>
    282 <li><b>small screen, portrait:</b> single pane, with logo</li>
    283 <li><b>small screen, landscape:</b> single pane, with logo</li>
    284 <li><b>7" tablet, portrait:</b> single pane, with action bar</li>
    285 <li><b>7" tablet, landscape:</b> dual pane, wide, with action bar</li>
    286 <li><b>10" tablet, portrait:</b> dual pane, narrow, with action bar</li>
    287 <li><b>10" tablet, landscape:</b> dual pane, wide, with action bar</li>
    288 <li><b>TV, landscape:</b> dual pane, wide, with action bar</li>
    289 </ul></p>
    290 
    291 <p>So each of these layouts is defined in an XML file in the 
    292 <code>res/layout/</code> directory. To then assign each layout to the various screen
    293 configurations, the app uses layout aliases to match them to
    294 each configuration:</p>
    295 
    296 <p><code>res/layout/onepane.xml:</code></p>
    297 {@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all}
    298 
    299 <p><code>res/layout/onepane_with_bar.xml:</code></p>
    300 {@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all}
    301 
    302 <p><code>res/layout/twopanes.xml</code>:</p>
    303 {@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all}
    304 
    305 <p><code>res/layout/twopanes_narrow.xml</code>:</p>
    306 {@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml all}
    307 
    308 <p>Now that all possible layouts are defined, it's just a matter of mapping the correct layout to
    309 each configuration using the configuration qualifiers. You can now do it using the layout alias
    310 technique:</p>
    311 
    312 <p><code>res/values/layouts.xml</code>:</p>
    313 {@sample development/samples/training/multiscreen/newsreader/res/values/layouts.xml all}
    314 
    315 <p><code>res/values-sw600dp-land/layouts.xml</code>:</p>
    316 {@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-land/layouts.xml
    317 all}
    318 
    319 <p><code>res/values-sw600dp-port/layouts.xml</code>:</p>
    320 {@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-port/layouts.xml
    321 all}
    322 
    323 <p><code>res/values-large-land/layouts.xml</code>:</p>
    324 {@sample development/samples/training/multiscreen/newsreader/res/values-large-land/layouts.xml all}
    325 
    326 <p><code>res/values-large-port/layouts.xml</code>:</p>
    327 {@sample development/samples/training/multiscreen/newsreader/res/values-large-port/layouts.xml all}
    328 
    329 
    330 
    331 <h2 id="TaskUse9Patch">Use Nine-patch Bitmaps</h2>
    332 
    333 <p>Supporting different screen sizes usually means that your image resources
    334 must also be capable of adapting to different sizes. For example, a button
    335 background must fit whichever button shape it is applied to.</p>
    336 
    337 <p>If you use simple images on components that can change size, you will
    338 quickly notice that the results are somewhat less than impressive, since the
    339 runtime will stretch or shrink your images uniformly. The solution is using nine-patch bitmaps,
    340 which are specially
    341 formatted PNG files that indicate which areas can and cannot be stretched.</p>
    342 
    343 <p>Therefore, when designing bitmaps that will be used on components with
    344 variable size, always use nine-patches. To convert a bitmap into a nine-patch,
    345 you can start with a regular image (figure 4, shown with in 4x zoom for clarity).</p>
    346 
    347 <img src="{@docRoot}images/training/button.png" />
    348 <p class="img-caption"><strong>Figure 4.</strong> <code>button.png</code></p>
    349 
    350 <p>And then run it through the <ode
    351 href="{@docRoot}tools/help/draw9patch.html"><code>draw9patch</code></a> utility of the
    352 SDK (which is located in the <code>tools/</code> directory), in which you can mark the areas that
    353 should be stretched by drawing pixels along the left and top borders. You can also mark the area
    354 that should hold the content by drawing pixels along the right and bottom borders, resulting in
    355 figure 5.</p>
    356 
    357 <img src="{@docRoot}images/training/button_with_marks.png" />
    358 <p class="img-caption"><strong>Figure 5.</strong> <code>button.9.png</code></p>
    359 
    360 <p>Notice the black pixels along the borders. The ones on the top and left
    361 borders indicate the places where the image can be stretched, and the ones on
    362 the right and bottom borders indicate where the content should be
    363 placed.</p>
    364 
    365 <p>Also, notice the <code>.9.png</code> extension. You must use this 
    366 extension, since this is how the framework detects that this is a nine-patch
    367 image, as opposed to a regular PNG image.</p>
    368 
    369 <p>When you apply this background to a component (by setting
    370 <code>android:background="&#64;drawable/button"</code>), the framework stretches
    371 the image correctly to accommodate the size of the button, as shown in various sizes in figure
    372 6.</p>
    373 
    374 <img src="{@docRoot}images/training/buttons_stretched.png" />
    375 <p class="img-caption"><strong>Figure 6.</strong> A button using the <code>button.9.png</code>
    376 nine-patch in various sizes.</p>
    377 
    378