1page.title=Creating a 2D Picker
2
3@jd:body
4
5<div id="tb-wrapper">
6<div id="tb">
7<h2>This lesson teaches you to</h2>
8<ol>
9  <li><a href="#add-page-grid">Add a Page Grid</a></li>
10  <li><a href="#implement-adapter">Implement a Page Adapter</a></li>
11</ol>
12<h2>Related Samples</h2>
13<ul>
14  <li><a href="{@docRoot}samples/GridViewPager/index.html">
15    GridViewPager</a></li>
16</ul>
17<h2>You should also read</h2>
18<ul>
19  <li><a href="{@docRoot}design/wear/index.html">Android Wear Design Principles</a></li>
20</ul>
21</div>
22</div>
23
24<p>The <a href="{@docRoot}design/wear/structure.html#2DPicker">2D Picker</a> pattern in Android
25Wear allows users to navigate and choose from a set of items shown as pages. The Wearable UI
26Library lets you easily implement this pattern using a page grid, which is a layout manager
27that allows users to scroll vertically and horizontally through pages of data.</p>
28
29<p>To implement this pattern, you add a
30<a href="{@docRoot}reference/android/support/wearable/view/GridViewPager.html"><code>GridViewPager</code></a>
31element to the layout of your activity and implement an adapter that provides a set of pages by
32extending the
33<a href="{@docRoot}reference/android/support/wearable/view/FragmentGridPagerAdapter.html"><code>FragmentGridPagerAdapter</code></a>
34class.</p>
35
36
37<h2 id="add-page-grid">Add a Page Grid</h2>
38
39<p>Add a
40<a href="{@docRoot}reference/android/support/wearable/view/GridViewPager.html"><code>GridViewPager</code></a>
41element to your layout definition as follows:</p>
42
43<pre>
44&lt;android.support.wearable.view.GridViewPager
45    xmlns:android="http://schemas.android.com/apk/res/android"
46    android:id="@+id/pager"
47    android:layout_width="match_parent"
48    android:layout_height="match_parent" />
49</pre>
50
51<p>You can use any of the techniques described in
52<a href="{@docRoot}training/wearables/ui/layouts.html">Defining Layouts</a> to ensure that
53your 2D picker works on both round and square devices.</p>
54
55
56<h2 id="implement-adapter">Implement a Page Adapter</h2>
57
58<p>A page adapter provides a set of pages to populate a
59<a href="{@docRoot}reference/android/support/wearable/view/GridViewPager.html"><code>GridViewPager</code></a>
60component. To implement this adapter, you extend the
61<a href="{@docRoot}reference/android/support/wearable/view/FragmentGridPagerAdapter.html"><code>FragmentGridPagerAdapter</code></a>
62class from the Wearable UI Library</p>
63
64<p>The following snippet shows how to provide a set of static cards with custom background
65images:</p>
66
67<pre>
68public class SampleGridPagerAdapter extends FragmentGridPagerAdapter {
69
70    private final Context mContext;
71    private List<Row> mRows;
72
73    public SampleGridPagerAdapter(Context ctx, FragmentManager fm) {
74        super(fm);
75        mContext = ctx;
76    }
77
78    static final int[] BG_IMAGES = new int[] {
79        R.drawable.debug_background_1, ...
80        R.drawable.debug_background_5
81    };
82
83    // A simple container for static data in each page
84    private static class Page {
85        // static resources
86        int titleRes;
87        int textRes;
88        int iconRes;
89        ...
90    }
91
92    // Create a static set of pages in a 2D array
93    private final Page[][] PAGES = { ... };
94
95    // Override methods in FragmentGridPagerAdapter
96    ...
97}
98</pre>
99
100<p>The adapter calls
101<a href="{@docRoot}reference/android/support/wearable/view/FragmentGridPagerAdapter.html#getFragment(int, int)"><code>getFragment()</code></a>
102and
103<a href="{@docRoot}reference/android/support/wearable/view/GridPagerAdapter.html#getBackgroundForRow(int)"><code>getBackgroundForRow()</code></a>
104to retrieve the content to display for each row:</p>
105
106<pre>
107// Obtain the UI fragment at the specified position
108&#64;Override
109public Fragment getFragment(int row, int col) {
110    Page page = PAGES[row][col];
111    String title =
112        page.titleRes != 0 ? mContext.getString(page.titleRes) : null;
113    String text =
114        page.textRes != 0 ? mContext.getString(page.textRes) : null;
115    CardFragment fragment = CardFragment.create(title, text, page.iconRes);
116
117    // Advanced settings (card gravity, card expansion/scrolling)
118    fragment.setCardGravity(page.cardGravity);
119    fragment.setExpansionEnabled(page.expansionEnabled);
120    fragment.setExpansionDirection(page.expansionDirection);
121    fragment.setExpansionFactor(page.expansionFactor);
122    return fragment;
123}
124
125// Obtain the background image for the row
126&#64;Override
127public Drawable getBackgroundForRow(int row) {
128    return mContext.getResources().getDrawable(
129            (BG_IMAGES[row % BG_IMAGES.length]), null);
130}
131
132</pre>
133
134<p>The following example shows how to retrieve the background to display for a specific page
135in the grid:
136</p>
137
138<pre>
139// Obtain the background image for the specific page
140&#64;Override
141public Drawable getBackgroundForPage(int row, int column) {
142    if( row == 2 && column == 1) {
143        // Place image at specified position
144        return mContext.getResources().getDrawable(R.drawable.bugdroid_large, null);
145    } else {
146        // Default to background image for row
147        return GridPagerAdapter.BACKGROUND_NONE;
148    }
149}
150</pre>
151
152<p>The
153<a href="{@docRoot}reference/android/support/wearable/view/GridPagerAdapter.html#getRowCount()"><code>getRowCount()</code></a>
154method tells the adapter how many rows of content are
155available, and the
156<a href="{@docRoot}reference/android/support/wearable/view/GridPagerAdapter.html#getColumnCount(int)"><code>getColumnCount()</code></a>
157method tells the adapter how many columns of content are available for each of the rows.</p>
158
159<pre>
160// Obtain the number of pages (vertical)
161&#64;Override
162public int getRowCount() {
163    return PAGES.length;
164}
165
166// Obtain the number of pages (horizontal)
167&#64;Override
168public int getColumnCount(int rowNum) {
169    return PAGES[rowNum].length;
170}
171</pre>
172
173<p>The adapter implementation details depend on your particular set of pages. Each page provided
174by the adapter is of type
175<a href="{@docRoot}reference/android/app/Fragment.html"><code>Fragment</code></a>.
176In this example, each page is a
177<a href="{@docRoot}reference/android/support/wearable/view/CardFragment.html"><code>CardFragment</code></a>
178instance that uses one of the default card layouts. However, you can combine different types of
179pages in the same 2D picker, such as cards, action icons, and custom layouts depending on your use
180cases.</p>
181
182<div style="float:right;margin-left:25px;width:250px">
183<img src="{@docRoot}wear/images/07_uilib.png" width="250" height="250" alt=""/>
184<p class="img-caption" style="text-align:center"><strong>Figure 1:</strong>
185The <em>GridViewPager</em> sample.</p>
186</div>
187
188<p>Not all rows need to have the same number of pages. Notice that in this example the number of
189colums is different for each row. You can also use a
190<a href="{@docRoot}reference/android/support/wearable/view/GridViewPager.html"><code>GridViewPager</code></a>
191component to implement a 1D picker with only one row or only one column.</p>
192
193<p>The
194<a href="{@docRoot}reference/android/support/wearable/view/GridViewPager.html"><code>GridViewPager</code></a>
195class provides support for scrolling in cards whose content does not fit
196the device screen. This example configures each card to expand as required, so users can scroll
197through the card's content. When users reach the end of a scrollable card, a swipe in the same
198direction shows the next page on the grid, if one is available.</p>
199
200<p>You can specify a custom background for each page with the
201<a href="{@docRoot}reference/android/support/wearable/view/GridPagerAdapter.html#getBackgroundForPage(int, int)"><code>getBackgroundForPage()</code></a>
202method. When users swipe to navigate across pages, the
203<a href="{@docRoot}reference/android/support/wearable/view/GridViewPager.html"><code>GridViewPager</code></a>
204class applies parallax and crossfade effects between different backgrounds automatically.</p>
205
206<h3>Assign an adapter instance to the page grid</h3>
207
208<p>In your activity, assign an instance of your adapter implementation to the
209<a href="{@docRoot}reference/android/support/wearable/view/GridViewPager.html"><code>GridViewPager</code></a>
210component:</p>
211
212<pre style="clear:both">
213public class MainActivity extends Activity {
214
215    &#64;Override
216    protected void onCreate(Bundle savedInstanceState) {
217        super.onCreate(savedInstanceState);
218        setContentView(R.layout.activity_main);
219        ...
220        final GridViewPager pager = (GridViewPager) findViewById(R.id.pager);
221        pager.setAdapter(new SampleGridPagerAdapter(this, getFragmentManager()));
222    }
223}
224</pre>
225