diff --git a/Android.mk b/Android.mk index 80e681c6a805c..371c370614311 100644 --- a/Android.mk +++ b/Android.mk @@ -448,6 +448,8 @@ web_docs_sample_code_flags := \ resources/samples/MultiResolution "Multiple Resolutions" \ -samplecode $(sample_dir)/NFCDemo \ resources/samples/NFCDemo "NFC Demo" \ + -samplecode $(sample_dir)/training/multiscreen/newsreader \ + resources/samples/newsreader "News Reader" \ -samplecode $(sample_dir)/NotePad \ resources/samples/NotePad "Note Pad" \ -samplecode $(sample_dir)/SpellChecker/SampleSpellCheckerService \ diff --git a/docs/html/images/training/button.png b/docs/html/images/training/button.png new file mode 100755 index 0000000000000..1a7944fc4c9e8 Binary files /dev/null and b/docs/html/images/training/button.png differ diff --git a/docs/html/images/training/button_with_marks.png b/docs/html/images/training/button_with_marks.png new file mode 100755 index 0000000000000..06e0720a805d6 Binary files /dev/null and b/docs/html/images/training/button_with_marks.png differ diff --git a/docs/html/images/training/buttons_stretched.png b/docs/html/images/training/buttons_stretched.png new file mode 100755 index 0000000000000..bb67419976228 Binary files /dev/null and b/docs/html/images/training/buttons_stretched.png differ diff --git a/docs/html/images/training/layout-hvga.png b/docs/html/images/training/layout-hvga.png new file mode 100644 index 0000000000000..b3403007ab89c Binary files /dev/null and b/docs/html/images/training/layout-hvga.png differ diff --git a/docs/html/images/training/relativelayout1.png b/docs/html/images/training/relativelayout1.png new file mode 100644 index 0000000000000..0b593dcde9300 Binary files /dev/null and b/docs/html/images/training/relativelayout1.png differ diff --git a/docs/html/images/training/relativelayout2.png b/docs/html/images/training/relativelayout2.png new file mode 100644 index 0000000000000..341b286524af3 Binary files /dev/null and b/docs/html/images/training/relativelayout2.png differ diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js index 18f1547d0ed98..d96bfde7add7b 100644 --- a/docs/html/resources/resources-data.js +++ b/docs/html/resources/resources-data.js @@ -557,6 +557,16 @@ var ANDROID_RESOURCES = [ en: 'A sample application that shows how to use resource directory qualifiers to provide different resources for different screen configurations.' } }, + { + tags: ['sample', 'new', 'bestpractices'], + path: 'samples/newsreader/index.html', + title: { + en: 'News Reader' + }, + description: { + en: 'A sample app demonstrating best practices to support multiple screen sizes and densities.' + } + }, { tags: ['sample', 'data'], path: 'samples/NFCDemo/index.html', diff --git a/docs/html/resources/samples/images/NewsReader.png b/docs/html/resources/samples/images/NewsReader.png new file mode 100644 index 0000000000000..f44c6494f09d3 Binary files /dev/null and b/docs/html/resources/samples/images/NewsReader.png differ diff --git a/docs/html/shareables/training/NewsReader.zip b/docs/html/shareables/training/NewsReader.zip new file mode 100644 index 0000000000000..7dda41c7c273e Binary files /dev/null and b/docs/html/shareables/training/NewsReader.zip differ diff --git a/docs/html/training/multiscreen/adaptui.jd b/docs/html/training/multiscreen/adaptui.jd new file mode 100644 index 0000000000000..34e9d7df7f8d5 --- /dev/null +++ b/docs/html/training/multiscreen/adaptui.jd @@ -0,0 +1,258 @@ +page.title=Implementing Adaptative UI Flows +parent.title=Designing for Multiple Screens +parent.link=index.html + +trainingnavtop=true +previous.title=Supporting Different Screen Densities +previous.link=screendensities.html + +@jd:body + + + +
+
+ +

This lesson teaches you to

+ +
    +
  1. Determine the Current Layout
  2. +
  3. React According to Current Layout
  4. +
  5. Reuse Fragments in Other Activities
  6. +
  7. Handle Screen Configuration Changes
  8. +
+ +

You should also read

+ + + +

Try it out

+ +
+Download + the sample app +

NewsReader.zip

+
+ + +
+
+ +

Depending on the layout that your application is currently showing, the UI +flow may be different. For example, if your application is in the dual-pane +mode, clicking on an item on the left pane will simply display the content on +the right pane; if it is in single-pane mode, the content should be displayed +on its own (in a different activity).

+ + +

Determine the Current Layout

+ +

Since your implementation of each layout will be a little different, one of +the first things you will probably have to do is determine what layout the user is currently +viewing. For example, you might want to know whether the user is in "single +pane" mode or "dual pane" mode. You can do that by querying if a given view +exists and is visible:

+ +
+public class NewsReaderActivity extends FragmentActivity {
+    boolean mIsDualPane;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main_layout);
+
+        View articleView = findViewById(R.id.article);
+        mIsDualPane = articleView != null && 
+                        articleView.getVisibility() == View.VISIBLE;
+    }
+}
+
+ +

Notice that this code queries whether the "article" pane is available or not, +which is much more flexible than hard-coding a query for a specific layout.

+ +

Another example of how you can adapt to the existence of different +components is to check whether they are available before performing an operation on +them. For example, in the News Reader sample app, there is a button that opens a +menu, but that button only exists when running on versions older than Android 3.0 (because it's +function is taken over by the {@link android.app.ActionBar} on API level 11+). So, to add the event +listener for this button, you can do:

+ +
+Button catButton = (Button) findViewById(R.id.categorybutton);
+OnClickListener listener = /* create your listener here */;
+if (catButton != null) {
+    catButton.setOnClickListener(listener);
+}
+
+ + +

React According to Current Layout

+ +

Some actions may have a different result depending on the current layout. +For example, in the News Reader sample, clicking on a headline from the +headlines list opens the article in the right hand-side pane if the UI +is in dual pane mode, but will launch a separate activity if the UI is in +single-pane mode:

+ +
+@Override
+public void onHeadlineSelected(int index) {
+    mArtIndex = index;
+    if (mIsDualPane) {
+        /* display article on the right pane */
+        mArticleFragment.displayArticle(mCurrentCat.getArticle(index));
+    } else {
+        /* start a separate activity */
+        Intent intent = new Intent(this, ArticleActivity.class);
+        intent.putExtra("catIndex", mCatIndex);
+        intent.putExtra("artIndex", index);
+        startActivity(intent);
+    }
+}
+
+ +

Likewise, if the app is in dual-pane mode, it should set up the action bar +with tabs for navigation, whereas if the app is in single-pane mode, it should set +up navigation with a spinner widget. So your code should also check which case is +appropriate:

+ +
+final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" };
+
+public void onCreate(Bundle savedInstanceState) {
+    ....
+    if (mIsDualPane) {
+        /* use tabs for navigation */
+        actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS);
+        int i;
+        for (i = 0; i < CATEGORIES.length; i++) {
+            actionBar.addTab(actionBar.newTab().setText(
+                CATEGORIES[i]).setTabListener(handler));
+        }
+        actionBar.setSelectedNavigationItem(selTab);
+    }
+    else {
+        /* use list navigation (spinner) */
+        actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST);
+        SpinnerAdapter adap = new ArrayAdapter(this, 
+                R.layout.headline_item, CATEGORIES);
+        actionBar.setListNavigationCallbacks(adap, handler);
+    }
+}
+
+ + +

Reuse Fragments in Other Activities

+ +

A recurring pattern in designing for multiple screens is having a portion of +your interface that's implemented as a pane on some screen configurations and +as a separate activity on other configurations. For example, in the News Reader +sample, the news article text is presented in the right side pane on +large screens, but is a separate activity on smaller screens.

+ +

In cases like this, you can usually avoid code duplication by reusing the +same {@link android.app.Fragment} subclass in several activities. For example, +ArticleFragment +is used in the dual-pane layout:

+ +{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +

And reused (without a layout) in the activity layout for smaller screens +(ArticleActivity):

+ +
+ArticleFragment frag = new ArticleFragment();
+getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit();
+
+ +

Naturally, this has the same effect as declaring the fragment in an XML +layout, but in this case an XML layout is unnecessary work because the article fragment +is the only component of this activity.

+ +

One very important point to keep in mind when designing your fragments is +to not create a strong coupling to a specific activity. You can usually do that +by defining an interface that abstracts all the ways in which the fragment +needs to interact with its host activity, and then the host activity +implements that interface:

+ +

For example, the News Reader app's HeadlinesFragment does precisely that:

+ +
+public class HeadlinesFragment extends ListFragment {
+    ...
+    OnHeadlineSelectedListener mHeadlineSelectedListener = null;
+
+    /* Must be implemented by host activity */
+    public interface OnHeadlineSelectedListener {
+        public void onHeadlineSelected(int index);
+    }
+    ...
+
+    public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) {
+        mHeadlineSelectedListener = listener;
+    }
+}
+
+ +

Then, when the user selects a headline, the fragment notifies the listener specified by the host +activity (as opposed to notifying a specific hard-coded activity):

+ +
+public class HeadlinesFragment extends ListFragment {
+    ...
+    @Override
+    public void onItemClick(AdapterView<?> parent, 
+                            View view, int position, long id) {
+        if (null != mHeadlineSelectedListener) {
+            mHeadlineSelectedListener.onHeadlineSelected(position);
+        }
+    }
+    ...
+}
+
+ +

This technique is discussed further in the guide to Supporting Tablets and Handsets.

+ + +

Handle Screen Configuration Changes

+ +

If you are using separate activities to implement separate parts of your interface, +you have to keep in mind that it may be necessary to react to certain +configuration changes (such as a rotation change) in order to keep your +interface consistent.

+ +

For example, on a typical 7" tablet running Android 3.0 or higher, the News Reader sample uses a +separate activity to display the news article when running in portrait mode, +but uses a two-pane layout when in landscape mode.

+ +

This means that when the user is in portrait mode and the activity for viewing an article is +onscreen, you need to detect that the orientation changed to landscape and +react appropriately by ending the activity and return to the main activity so the content can +display in the two-pane layout:

+ +
+public class ArticleActivity extends FragmentActivity {
+    int mCatIndex, mArtIndex;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mCatIndex = getIntent().getExtras().getInt("catIndex", 0);
+        mArtIndex = getIntent().getExtras().getInt("artIndex", 0);
+
+        // If should be in two-pane mode, finish to return to main activity
+        if (getResources().getBoolean(R.bool.has_two_panes)) {
+            finish();
+            return;
+        }
+        ...
+}
+
+ + diff --git a/docs/html/training/multiscreen/index.jd b/docs/html/training/multiscreen/index.jd new file mode 100644 index 0000000000000..a986cef188047 --- /dev/null +++ b/docs/html/training/multiscreen/index.jd @@ -0,0 +1,87 @@ +page.title=Designing for Multiple Screens + +trainingnavtop=true +startpage=true +next.title=Supporting Different Screen Sizes +next.link=screensizes.html + +@jd:body + +
+
+ +

Dependencies and prerequisites

+ + + +

You should also read

+ + + +

Try it out

+ +
+Download + the sample app +

NewsReader.zip

+
+ +
+
+ +

Android powers hundreds of device types with several different screen sizes, +ranging from small phones to large TV sets. Therefore, it’s important +that you design your application to be compatible with all screen sizes so it’s available to as many +users as possible.

+ +

But being compatible with different device types is not enough. Each screen +size offers different possibilities and challenges for user interaction, so in +order to truly satisfy and impress your users, your application must go beyond merely +supporting multiple screens: it must optimize the user +experience for each screen configuration.

+ +

This class shows you how to implement a user interface that's +optimized for several screen configurations.

+ +

The code in each lesson comes from a sample application that demonstrates best practices in +optimizing for multiple screens. You can download the sample (to the right) and use it as a source +of reusable code for your own application.

+ +

Note: This class and the associated sample use the support library in order to use the {@link +android.app.Fragment} APIs on versions lower than Android 3.0. You must download and add the +library to your application in order to use all APIs in this class.

+ + +

Lessons

+ +
+
Supporting Different Screen Sizes
+
This lesson walks you through how to design layouts that adapts + several different screen sizes (using flexible dimensions for + views, {@link android.widget.RelativeLayout}, screen size and orientation qualifiers, + alias filters, and nine-patch bitmaps).
+ +
Supporting Different Screen + Densities
+
This lesson shows you how to support screens that have different + pixel densities (using density-independent pixels and providing + bitmaps appropriate for each density).
+ +
Implementing Adaptative UI Flows
+
This lesson shows you how to implement your UI flow in a way + that adapts to several screen size/density combinations + (run-time detection of active layout, reacting according to + current layout, handling screen configuration changes).
+
diff --git a/docs/html/training/multiscreen/screendensities.jd b/docs/html/training/multiscreen/screendensities.jd new file mode 100644 index 0000000000000..7d6ff4486f1d2 --- /dev/null +++ b/docs/html/training/multiscreen/screendensities.jd @@ -0,0 +1,127 @@ +page.title=Supporting Different Densities +parent.title=Designing for Multiple Screens +parent.link=index.html + +trainingnavtop=true +previous.title=Supporting Different Screen Sizes +previous.link=screensizes.html +next.title=Implementing Adaptative UI Flows +next.link=adaptui.html + +@jd:body + + + +
+
+ +

This lesson teaches you to

+
    +
  1. Use Density-independent Pixels
  2. +
  3. Provide Alternative Bitmaps
  4. +
+ +

You should also read

+ + + +

Try it out

+ +
+Download + the sample app +

NewsReader.zip

+
+ + +
+
+ +

This lesson shows you how to support different screen densities +by providing different resources and using resolution-independent units of +measurements.

+ +

Use Density-independent Pixels

+ +

One common pitfall you must avoid when designing your layouts is using +absolute pixels to define distances or sizes. Defining layout dimensions with +pixels is a problem because different screens have different pixel densities, +so the same number of pixels may correspond to different physical sizes on +different devices. Therefore, when specifying dimensions, always use either +dp or sp units. A dp is a density-independent pixel +that corresponds to the physical size of a pixel at 160 dpi. An sp is the same +base unit, but is scaled by the user's preferred text size (it’s a +scale-independent pixel), so you should use this measurement unit when defining +text size (but never for layout sizes).

+ +

For example, when you specify spacing between two views, use dp +rather than px:

+ +
+<Button android:layout_width="wrap_content" 
+    android:layout_height="wrap_content" 
+    android:text="@string/clickme"
+    android:layout_marginTop="20dp" />
+
+ +

When specifying text size, always use sp:

+ +
+<TextView android:layout_width="match_parent" 
+    android:layout_height="wrap_content" 
+    android:textSize="20sp" />
+
+ + +

Provide Alternative Bitmaps

+ +

Since Android runs in devices with a wide variety of screen densities, +you should always provide your bitmap resources tailored to each of +the generalized density buckets: low, medium, high and extra-high density. +This will help you achieve good graphical quality and performance on all +screen densities.

+ +

To generate these images, you should start with your raw resource in +vector format and generate the images for each density using the following +size scale:

+ +

+ +

This means that if you generate a 200x200 image for xhdpi +devices, you should generate the same resource in 150x150 for hdpi, +100x100 for mdpi and finally a 75x75 image for ldpi +devices.

+ +

Then, place the generated image files in the appropriate subdirectory +under res/ and the system will pick the correct one automatically +based on the screen density of the device your application is running on:

+ +
+MyProject/
+  res/
+    drawable-xhdpi/
+        awesomeimage.png
+    drawable-hdpi/
+        awesomeimage.png
+    drawable-mdpi/
+        awesomeimage.png
+    drawable-ldpi/
+        awesomeimage.png
+
+ +

Then, any time you reference @drawable/awesomeimage, the system selects the +appropriate bitmap based on the screen's dpi.

+ +

For more tips and guidelines for creating icon assets for your application, see the Icon Design +Guidelines.

+ diff --git a/docs/html/training/multiscreen/screensizes.jd b/docs/html/training/multiscreen/screensizes.jd new file mode 100644 index 0000000000000..2db0b67bb9223 --- /dev/null +++ b/docs/html/training/multiscreen/screensizes.jd @@ -0,0 +1,376 @@ +page.title=Supporting Different Screen Sizes +parent.title=Designing for Multiple Screens +parent.link=index.html + +trainingnavtop=true +next.title=Supporting Different Screen Densities +next.link=screendensities.html + +@jd:body + + + +
+
+ +

This lesson teaches you to

+
    +
  1. Use "wrap_content" and "match_parent"
  2. +
  3. Use RelativeLayout
  4. +
  5. Use Size Qualifiers
  6. +
  7. Use the Smallest-width Qualifier
  8. +
  9. Use Layout Aliases
  10. +
  11. Use Orientation Qualifiers
  12. +
  13. Use Nine-patch Bitmaps
  14. +
+ +

You should also read

+ + + +

Try it out

+ +
+Download + the sample app +

NewsReader.zip

+
+ +
+
+ +

This lesson shows you how to support different screen sizes by:

+ + + +

Use "wrap_content" and "match_parent"

+ +

To ensure that your layout is flexible and adapts to different screen sizes, +you should use "wrap_content" and "match_parent" for the width +and height of some view components. If you use "wrap_content", the width +or height of the view is set to the minimum size necessary to fit the content +within that view, while "match_parent" (also known as +"fill_parent" before API level 8) makes the component expand to match the size of its +parent view.

+ +

By using the "wrap_content" and "match_parent" size values instead of +hard-coded sizes, your views either use only the space required for that +view or expand to fill the available space, respectively. For example:

+ +{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +

Notice how the sample uses "wrap_content" and "match_parent" +for component sizes rather than specific dimensions. This allows the layout +to adapt correctly to different screen sizes and orientations.

+ +

For example, this is what this layout looks like in portrait and landscape +mode. Notice that the sizes of the components adapt automatically to the +width and height:

+ + +

Figure 1. The News Reader sample app in portrait (left) +and landscape (right).

+ + +

Use RelativeLayout

+ +

You can construct fairly complex layouts using nested instances of {@link +android.widget.LinearLayout} and +combinations of "wrap_content" and "match_parent" sizes. +However, {@link android.widget.LinearLayout} does not allow you to precisely control the +spacial relationships of child views; views in a {@link android.widget.LinearLayout} simply line up +side-by-side. If you need child views to be oriented in variations other than a straight line, a +better solution is often to use a {@link android.widget.RelativeLayout}, which allows +you to specify your layout in terms of the spacial relationships between +components. For instance, you can align one child view on the left side and another view on +the right side of the screen.

+ +

For example:

+ +
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <TextView
+        android:id="@+id/label"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="Type here:"/>
+    <EditText
+        android:id="@+id/entry"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/label"/>
+    <Button
+        android:id="@+id/ok"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/entry"
+        android:layout_alignParentRight="true"
+        android:layout_marginLeft="10dp"
+        android:text="OK" />
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toLeftOf="@id/ok"
+        android:layout_alignTop="@id/ok"
+        android:text="Cancel" />
+</RelativeLayout>
+
+ +

Figure 2 shows how this layout appears on a QVGA screen.

+ + +

Figure 2. Screenshot on a QVGA screen (small screen).

+ +

Figure 3 shows how it appears on a larger screen.

+ + +

Figure 3. Screenshot on a WSVGA screen (large screen).

+ +

Notice that although the size of the components changed, their +spatial relationships are preserved as specified by the {@link +android.widget.RelativeLayout.LayoutParams}.

+ + +

Use Size Qualifiers

+ +

There's only so much mileage you can get from a flexible layout or relative layout +like the one in the previous sections. While those layouts adapt to +different screens by stretching the space within and around components, they +may not provide the best user experience for each screen size. Therefore, your +application should not only implement flexible layouts, but should also provide +several alternative layouts to target different screen configurations. You do +so by using configuration qualifiers, which allows the runtime +to automatically select the appropriate resource based on the current device’s +configuration (such as a different layout design for different screen sizes).

+ +

For example, many applications implement the "two pane" pattern for large +screens (the app might show a list of items on one pane and the content on +another pane). Tablets and TVs are large enough for both panes to fit +simultaneously on screen, but phone screens have to show them separately. So, +to implement these layouts, you could have the following files:

+ + + +

Notice the xlarge qualifier in the directory name of the second layout. This layout +will be selected on devices with screens classified as extra-large (for example, 10" tablets). The +other layout (without qualifiers) will be selected for smaller devices.

+ + +

Use the Smallest-width Qualifier

+ +

One of the difficulties developers had in pre-3.2 Android devices was the +"large" screen size bin, which encompasses the Dell Streak, the original Galaxy +Tab, and 7" tablets in general. However, many applications may want to show +different layouts for different devices in this category (such as for 5" and 7" devices), even +though they are all considered to be "large" screens. That's why Android introduced the +"Smallest-width" qualifier (amongst others) in Android 3.2.

+ +

The Smallest-width qualifier allows you to target screens that have a certain minimum +width given in dp. For example, the typical 7" tablet has a minimum width of +600 dp, so if you want your UI to have two panes on those screens (but a single +list on smaller screens), you can use the same two layouts from the previous section for single +and two-pane layouts, but instead of the xlarge size qualifier, use +sw600dp to indicate the two-pane layout is for screens on which the smallest-width +is 600 dp:

+ + + +

This means that devices whose smallest width is greater than or equal to +600dp will select the layout-sw600dp/main.xml (two-pane) layout, +while smaller screens will select the layout/main.xml (single-pane) +layout.

+ +

However, this won't work well on pre-3.2 devices, because they don't +recognize sw600dp as a size qualifier, so you still have to use the xlarge +qualifier as well. So, you should have a file named +res/layout-xlarge/main.xml +which is identical to res/layout-sw600dp/main.xml. In the next section +you'll see a technique that allows you to avoid duplicating the layout files this way.

+ + +

Use Layout Aliases

+ +

The smallest-width qualifier is available only on Android 3.2 and above. +Therefore, you should also still use the abstract size bins (small, normal, +large and xlarge) to be compatible with earlier versions. For example, if you +want to design your UI so that it shows a single-pane UI on phones but a +multi-pane UI on 7" tablets and larger devices, you'd have to supply these +files:

+ +

+ +

The last two files are identical, because one of them will be matched by +Android 3.2 devices, and the other one is for the benefit of tablets with +earlier versions of Android.

+ +

To avoid this duplication of the same file for tablets (and the maintenance +headache resulting from it), you can use alias files. For example, you can define the following +layouts:

+ + + +

And add these two files:

+ +

+ +

These latter two files have identical content, but they don’t actually define +the layout. They merely set up {@code main} to be an alias to {@code main_twopanes}. Since +these files have xlarge and sw600dp selectors, they are +applied to tablets regardless of Android version (pre-3.2 tablets match +{@code xlarge}, and post-3.2 will match sw600dp).

+ + +

Use Orientation Qualifiers

+ +

Some layouts work well in both landscape and portrait orientations, but most of them can +benefit from adjustments. In the News Reader sample app, here is how the layout +behaves in each screen size and orientation:

+ +

+ +

So each of these layouts is defined in an XML file in the +res/layout/ directory. To then assign each layout to the various screen +configurations, the app uses layout aliases to match them to +each configuration:

+ +

res/layout/onepane.xml:

+{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane.xml all} + +

res/layout/onepane_with_bar.xml:

+{@sample development/samples/training/multiscreen/newsreader/res/layout/onepane_with_bar.xml all} + +

res/layout/twopanes.xml:

+{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes.xml all} + +

res/layout/twopanes_narrow.xml:

+{@sample development/samples/training/multiscreen/newsreader/res/layout/twopanes_narrow.xml all} + +

Now that all possible layouts are defined, it's just a matter of mapping the correct layout to +each configuration using the configuration qualifiers. You can now do it using the layout alias +technique:

+ +

res/values/layouts.xml:

+{@sample development/samples/training/multiscreen/newsreader/res/values/layouts.xml all} + +

res/values-sw600dp-land/layouts.xml:

+{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-land/layouts.xml +all} + +

res/values-sw600dp-port/layouts.xml:

+{@sample development/samples/training/multiscreen/newsreader/res/values-sw600dp-port/layouts.xml +all} + +

res/values-xlarge-land/layouts.xml:

+{@sample development/samples/training/multiscreen/newsreader/res/values-xlarge-land/layouts.xml all} + +

res/values-xlarge-port/layouts.xml:

+{@sample development/samples/training/multiscreen/newsreader/res/values-xlarge-port/layouts.xml all} + + + +

Use Nine-patch Bitmaps

+ +

Supporting different screen sizes usually means that your image resources +must also be capable of adapting to different sizes. For example, a button +background must fit whichever button shape it is applied to.

+ +

If you use simple images on components that can change size, you will +quickly notice that the results are somewhat less than impressive, since the +runtime will stretch or shrink your images uniformly. The solution is using nine-patch bitmaps, +which are specially +formatted PNG files that indicate which areas can and cannot be stretched.

+ +

Therefore, when designing bitmaps that will be used on components with +variable size, always use nine-patches. To convert a bitmap into a nine-patch, +you can start with a regular image (figure 4, shown with in 4x zoom for clarity).

+ + +

Figure 4. button.png

+ +

And then run it through the draw9patch utility of the +SDK (which is located in the tools/ directory), in which you can mark the areas that +should be stretched by drawing pixels along the left and top borders. You can also mark the area +that should hold the content by drawing pixels along the right and bottom borders, resulting in +figure 5.

+ + +

Figure 5. button.9.png

+ +

Notice the black pixels along the borders. The ones on the top and left +borders indicate the places where the image can be stretched, and the ones on +the right and bottom borders indicate where the content should be +placed.

+ +

Also, notice the .9.png extension. You must use this +extension, since this is how the framework detects that this is a nine-patch +image, as opposed to a regular PNG image.

+ +

When you apply this background to a component (by setting +android:background="@drawable/button"), the framework stretches +the image correctly to accommodate the size of the button, as shown in various sizes in figure +6.

+ + +

Figure 6. A button using the button.9.png +nine-patch in various sizes.

+