1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
|
page.title=Creating Swipe Views with Tabs
page.tags="viewpager","horizontal","paging","swipe view","tabs"
trainingnavtop=true
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#horizontal-paging">Implement Swipe Views</a></li>
<li><a href="#tabs">Add Tabs to the Action Bar</a></li>
<li><a href="#swipe-tabs">Change Tabs with Swipe Views</a></li>
<li><a href="#PagerTitleStrip">Use a Title Strip Instead of Tabs</a></li>
</ol>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}training/design-navigation/descendant-lateral.html">Providing Descendant and Lateral Navigation</a></li>
<li><a href="{@docRoot}design/building-blocks/tabs.html">Android Design: Tabs</a></li>
<li><a href="{@docRoot}design/patterns/swipe-views.html">Android Design: Swipe Views</a></li>
</ul>
<h2>Try it out</h2>
<div class="download-box">
<a href="http://developer.android.com/shareables/training/EffectiveNavigation.zip"
class="button">Download the sample app</a>
<p class="filename">EffectiveNavigation.zip</p>
</div>
</div>
</div>
<p>Swipe views provide lateral navigation between sibling screens such as tabs with
a horizontal finger gesture (a pattern sometimes known as horizontal paging). This lesson teaches
you how to create a tab layout with swipe views for switching between tabs, or how to show
a title strip instead of tabs.</p>
<div class="note design">
<p><strong>Swipe View Design</strong></p>
<p>Before implementing these features, you should understand the concepts and recommendations
as described in <a href="{@docRoot}training/design-navigation/descendant-lateral.html">Designing
Effective Navigation</a> and the <a href="{@docRoot}design/patterns/swipe-views.html">Swipe
Views</a> design guide.</p>
</div>
<h2 id="horizontal-paging">Implement Swipe Views</h2>
<p>You can create swipe views in your app using the {@link android.support.v4.view.ViewPager}
widget, available in the
<a href="{@docRoot}tools/support-library/index.html">Support Library</a>. The
{@link android.support.v4.view.ViewPager} is a layout widget in which each child view is
a separate page (a separate tab) in the layout.</p>
<p>To set up your layout with {@link android.support.v4.view.ViewPager}, add a
{@code <ViewPager>} element to your XML layout. For example, if each page in the swipe view
should consume the entire layout, then your layout looks like this:</p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</pre>
<p>To insert child views that represent each page,
you need to hook this layout to a {@link android.support.v4.view.PagerAdapter}.
There are two kinds of adapter you can use:</p>
<dl>
<dt>{@link android.support.v4.app.FragmentPagerAdapter}</dt>
<dd>This is best when navigating between sibling screens representing a fixed, small
number of pages.</dd>
<dt>{@link android.support.v4.app.FragmentStatePagerAdapter}</dt>
<dd>This is best for paging across a collection of objects
for which the number of pages is undetermined. It destroys
fragments as the user navigates to other pages, minimizing memory usage.</dd>
</dl>
<p>For example, here's how you might use {@link android.support.v4.app.FragmentStatePagerAdapter}
to swipe across a collection of {@link android.app.Fragment} objects:</p>
<pre>
public class CollectionDemoActivity extends FragmentActivity {
// When requested, this adapter returns a DemoObjectFragment,
// representing an object in the collection.
DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
ViewPager mViewPager;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection_demo);
// ViewPager and its adapters use support library
// fragments, so use getSupportFragmentManager.
mDemoCollectionPagerAdapter =
new DemoCollectionPagerAdapter(
getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
}
}
// Since this is an object collection, use a FragmentStatePagerAdapter,
// and NOT a FragmentPagerAdapter.
public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
{@literal @}Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
// Our object is just an integer :-P
args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1);
fragment.setArguments(args);
return fragment;
}
{@literal @}Override
public int getCount() {
return 100;
}
{@literal @}Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
// Instances of this class are fragments representing a single
// object in our collection.
public static class DemoObjectFragment extends Fragment {
public static final String ARG_OBJECT = "object";
{@literal @}Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
// The last two arguments ensure LayoutParams are inflated
// properly.
View rootView = inflater.inflate(
R.layout.fragment_collection_object, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1)).setText(
Integer.toString(args.getInt(ARG_OBJECT)));
return rootView;
}
}
</pre>
<p>This example shows only the code necessary to create the swipe views. The following
sections show how you can add tabs to help facilitate navigation between pages.</p>
<h2 id="tabs">Add Tabs to the Action Bar</h2>
<p>Action bar
<a href="{@docRoot}design/building-blocks/tabs.html">tabs</a> offer users a familiar interface
for navigating between and identifying sibling screens in your app.</p>
<p>To create tabs using {@link android.app.ActionBar}, you need to enable
{@link android.app.ActionBar#NAVIGATION_MODE_TABS}, then create several instances of
{@link android.app.ActionBar.Tab} and supply an implementation of
the {@link android.app.ActionBar.TabListener} interface for each one.
For example, in your activity's {@link
android.app.Activity#onCreate onCreate()} method, you can use code similar to this:</p>
<pre>
{@literal @}Override
public void onCreate(Bundle savedInstanceState) {
final ActionBar actionBar = getActionBar();
...
// Specify that tabs should be displayed in the action bar.
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create a tab listener that is called when the user changes tabs.
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
// show the given tab
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
// hide the given tab
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// probably ignore this event
}
};
// Add 3 tabs, specifying the tab's text and TabListener
for (int i = 0; i < 3; i++) {
actionBar.addTab(
actionBar.newTab()
.setText("Tab " + (i + 1))
.setTabListener(tabListener));
}
}
</pre>
<p>How you handle the {@link android.app.ActionBar.TabListener} callbacks to change tabs
depends on how you've constructed your content. But if you're using fragments for each tab with
{@link android.support.v4.view.ViewPager} as shown above, the following
section shows how to switch between pages when the user selects a tab and also update the selected
tab when the user swipes between pages.</p>
<h2 id="swipe-tabs">Change Tabs with Swipe Views</h2>
<p>To switch between pages in a {@link android.support.v4.view.ViewPager} when the user selects
a tab, implement your {@link android.app.ActionBar.TabListener} to select the appropriate page
by calling {@link android.support.v4.view.ViewPager#setCurrentItem setCurrentItem()} on your
{@link android.support.v4.view.ViewPager}:</p>
<pre>
{@literal @}Override
public void onCreate(Bundle savedInstanceState) {
...
// Create a tab listener that is called when the user changes tabs.
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
// When the tab is selected, switch to the
// corresponding page in the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
...
};
}
</pre>
<p>Likewise, you should select the corresponding tab when the user swipes between pages with a
touch gesture. You can set up this behavior by implementing the
{@link android.support.v4.view.ViewPager.OnPageChangeListener} interface to change
the current tab each time the page changes. For example:</p>
<pre>
{@literal @}Override
public void onCreate(Bundle savedInstanceState) {
...
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
{@literal @}Override
public void onPageSelected(int position) {
// When swiping between pages, select the
// corresponding tab.
getActionBar().setSelectedNavigationItem(position);
}
});
...
}
</pre>
<h2 id="PagerTitleStrip">Use a Title Strip Instead of Tabs</h2>
<p>If you don't want to include action bar tabs and prefer to provide
<a href="{@docRoot}design/building-blocks/tabs.html#scrollable">scrollable tabs</a> for a shorter
visual profile, you can use {@link android.support.v4.view.PagerTitleStrip} with
your swipe views.</p>
<p>Below is an example layout XML file for an
activity whose entire contents are a {@link android.support.v4.view.ViewPager} and a top-aligned
{@link android.support.v4.view.PagerTitleStrip} inside it. Individual pages (provided by the
adapter) occupy the remaining space inside the {@link android.support.v4.view.ViewPager}.</p>
<pre>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.PagerTitleStrip
android:id="@+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:textColor="#fff"
android:paddingTop="4dp"
android:paddingBottom="4dp" />
</android.support.v4.view.ViewPager>
</pre>
|