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