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
|
package cgeo.geocaching.activity;
import cgeo.geocaching.R;
import cgeo.geocaching.utils.Log;
import com.viewpagerindicator.TitlePageIndicator;
import com.viewpagerindicator.TitleProvider;
import org.apache.commons.lang3.tuple.Pair;
import android.app.Activity;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.View;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Abstract activity with the ability to manage pages in a view pager.
*
* @param <Page>
* Enum listing all available pages of this activity. The pages available at a certain point of time are
* defined by overriding {@link #getOrderedPages()}.
*/
public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends AbstractActivity {
/**
* A {@link List} of all available pages.
*
* TODO Move to adapter
*/
private final List<Page> pageOrder = new ArrayList<Page>();
/**
* Instances of all {@link PageViewCreator}.
*/
private final Map<Page, PageViewCreator> viewCreators = new HashMap<Page, PageViewCreator>();
/**
* The {@link ViewPager} for this activity.
*/
private ViewPager viewPager;
/**
* The {@link ViewPagerAdapter} for this activity.
*/
private ViewPagerAdapter viewPagerAdapter;
/**
* The {@link TitlePageIndicator} for this activity.
*/
private TitlePageIndicator titleIndicator;
public interface PageViewCreator {
/**
* Returns a validated view.
*
* @return
*/
public View getDispatchedView();
/**
* Returns a (maybe cached) view.
*
* @return
*/
public View getView();
/**
* Handles changed data-sets.
*/
public void notifyDataSetChanged();
}
/**
* Page selection interface for the view pager.
*
*/
protected interface OnPageSelectedListener {
public void onPageSelected(int position);
}
/**
* The ViewPagerAdapter for scrolling through pages of the CacheDetailActivity.
*/
private class ViewPagerAdapter extends PagerAdapter implements TitleProvider {
@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
@Override
public void finishUpdate(View container) {
}
@Override
public int getCount() {
return pageOrder.size();
}
@Override
public Object instantiateItem(View container, int position) {
final Page page = pageOrder.get(position);
PageViewCreator creator = viewCreators.get(page);
if (null == creator && null != page) {
creator = AbstractViewPagerActivity.this.createViewCreator(page);
viewCreators.put(page, creator);
}
View view = null;
try {
if (null != creator) {
// Result from getView() is maybe cached, but it should be valid because the
// creator should be informed about data-changes with notifyDataSetChanged()
view = creator.getView();
((ViewPager) container).addView(view, 0);
}
} catch (Exception e) {
Log.e("ViewPagerAdapter.instantiateItem ", e);
}
return view;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void startUpdate(View arg0) {
}
@Override
public int getItemPosition(Object object) {
// We are doing the caching. So pretend that the view is gone.
// The ViewPager will get it back in instantiateItem()
return POSITION_NONE;
}
@Override
public String getTitle(int position) {
final Page page = pageOrder.get(position);
if (null == page) {
return "";
}
return AbstractViewPagerActivity.this.getTitle(page);
}
}
/**
* Create the view pager. Call this from the {@link Activity#onCreate} implementation.
*
* @param startPageIndex
* index of the page shown first
* @param pageSelectedListener
* page selection listener or <code>null</code>
*/
protected final void createViewPager(int startPageIndex, final OnPageSelectedListener pageSelectedListener) {
// initialize ViewPager
viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPagerAdapter = new ViewPagerAdapter();
viewPager.setAdapter(viewPagerAdapter);
titleIndicator = (TitlePageIndicator) findViewById(R.id.pager_indicator);
titleIndicator.setViewPager(viewPager);
if (pageSelectedListener != null) {
titleIndicator.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
pageSelectedListener.onPageSelected(position);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
// switch to entry page (last used or 2)
if (viewPagerAdapter.getCount() < startPageIndex) {
for (int i = 0; i <= startPageIndex; i++) {
// we can't switch to a page that is out of bounds, so we add null-pages
pageOrder.add(null);
}
}
viewPager.setCurrentItem(startPageIndex, false);
}
/**
* create the view creator for the given page
*
* @return new view creator
*/
protected abstract PageViewCreator createViewCreator(Page page);
/**
* get the title for the given page
*/
protected abstract String getTitle(Page page);
protected final void reinitializeViewPager() {
// notify all creators that the data has changed
for (PageViewCreator creator : viewCreators.values()) {
creator.notifyDataSetChanged();
}
pageOrder.clear();
final Pair<List<? extends Page>, Integer> pagesAndIndex = getOrderedPages();
pageOrder.addAll(pagesAndIndex.getLeft());
// switch to details page, if we're out of bounds
final int defaultPage = pagesAndIndex.getRight();
if (getCurrentItem() < 0 || getCurrentItem() >= viewPagerAdapter.getCount()) {
viewPager.setCurrentItem(defaultPage, false);
}
// notify the adapter that the data has changed
viewPagerAdapter.notifyDataSetChanged();
// notify the indicator that the data has changed
titleIndicator.notifyDataSetChanged();
}
/**
* @return the currently available list of ordered pages, together with the index of the default page
*/
protected abstract Pair<List<? extends Page>, Integer> getOrderedPages();
public final Page getPage(int position) {
return pageOrder.get(position);
}
protected final int getPageIndex(Page page) {
return pageOrder.indexOf(page);
}
protected final PageViewCreator getViewCreator(Page page) {
return viewCreators.get(page);
}
protected final boolean isCurrentPage(Page page) {
return getCurrentItem() == getPageIndex(page);
}
protected int getCurrentItem() {
return viewPager.getCurrentItem();
}
}
|