1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.widget;
18 
19 import android.database.DataSetObservable;
20 import android.database.DataSetObserver;
21 import android.os.Parcelable;
22 import android.view.View;
23 import android.view.ViewGroup;
24 
25 /**
26  * Base class providing the adapter to populate pages inside of
27  * a {@link android.support.v4.view.ViewPager}.  You will most likely want to use a more
28  * specific implementation of this, such as
29  * {@link android.support.v4.app.FragmentPagerAdapter} or
30  * {@link android.support.v4.app.FragmentStatePagerAdapter}.
31  *
32  * <p>When you implement a PagerAdapter, you must override the following methods
33  * at minimum:</p>
34  * <ul>
35  * <li>{@link #instantiateItem(android.view.ViewGroup, int)}</li>
36  * <li>{@link #destroyItem(android.view.ViewGroup, int, Object)}</li>
37  * <li>{@link #getCount()}</li>
38  * <li>{@link #isViewFromObject(android.view.View, Object)}</li>
39  * </ul>
40  *
41  * <p>PagerAdapter is more general than the adapters used for
42  * {@link android.widget.AdapterView AdapterViews}. Instead of providing a
43  * View recycling mechanism directly ViewPager uses callbacks to indicate the
44  * steps taken during an update. A PagerAdapter may implement a form of View
45  * recycling if desired or use a more sophisticated method of managing page
46  * Views such as Fragment transactions where each page is represented by its
47  * own Fragment.</p>
48  *
49  * <p>ViewPager associates each page with a key Object instead of working with
50  * Views directly. This key is used to track and uniquely identify a given page
51  * independent of its position in the adapter. A call to the PagerAdapter method
52  * {@link #startUpdate(android.view.ViewGroup)} indicates that the contents of the ViewPager
53  * are about to change. One or more calls to {@link #instantiateItem(android.view.ViewGroup, int)}
54  * and/or {@link #destroyItem(android.view.ViewGroup, int, Object)} will follow, and the end
55  * of an update will be signaled by a call to {@link #finishUpdate(android.view.ViewGroup)}.
56  * By the time {@link #finishUpdate(android.view.ViewGroup) finishUpdate} returns the views
57  * associated with the key objects returned by
58  * {@link #instantiateItem(android.view.ViewGroup, int) instantiateItem} should be added to
59  * the parent ViewGroup passed to these methods and the views associated with
60  * the keys passed to {@link #destroyItem(android.view.ViewGroup, int, Object) destroyItem}
61  * should be removed. The method {@link #isViewFromObject(android.view.View, Object)} identifies
62  * whether a page View is associated with a given key object.</p>
63  *
64  * <p>A very simple PagerAdapter may choose to use the page Views themselves
65  * as key objects, returning them from {@link #instantiateItem(android.view.ViewGroup, int)}
66  * after creation and adding them to the parent ViewGroup. A matching
67  * {@link #destroyItem(android.view.ViewGroup, int, Object)} implementation would remove the
68  * View from the parent ViewGroup and {@link #isViewFromObject(android.view.View, Object)}
69  * could be implemented as <code>return view == object;</code>.</p>
70  *
71  * <p>PagerAdapter supports data set changes. Data set changes must occur on the
72  * main thread and must end with a call to {@link #notifyDataSetChanged()} similar
73  * to AdapterView adapters derived from {@link android.widget.BaseAdapter}. A data
74  * set change may involve pages being added, removed, or changing position. The
75  * ViewPager will keep the current page active provided the adapter implements
76  * the method {@link #getItemPosition(Object)}.</p>
77  */
78 public abstract class PagerAdapter {
79     private DataSetObservable mObservable = new DataSetObservable();
80 
81     public static final int POSITION_UNCHANGED = -1;
82     public static final int POSITION_NONE = -2;
83 
84     /**
85      * Return the number of views available.
86      */
getCount()87     public abstract int getCount();
88 
89     /**
90      * Called when a change in the shown pages is going to start being made.
91      * @param container The containing View which is displaying this adapter's
92      * page views.
93      */
startUpdate(ViewGroup container)94     public void startUpdate(ViewGroup container) {
95         startUpdate((View) container);
96     }
97 
98     /**
99      * Create the page for the given position.  The adapter is responsible
100      * for adding the view to the container given here, although it only
101      * must ensure this is done by the time it returns from
102      * {@link #finishUpdate(android.view.ViewGroup)}.
103      *
104      * @param container The containing View in which the page will be shown.
105      * @param position The page position to be instantiated.
106      * @return Returns an Object representing the new page.  This does not
107      * need to be a View, but can be some other container of the page.
108      */
instantiateItem(ViewGroup container, int position)109     public Object instantiateItem(ViewGroup container, int position) {
110         return instantiateItem((View) container, position);
111     }
112 
113     /**
114      * Remove a page for the given position.  The adapter is responsible
115      * for removing the view from its container, although it only must ensure
116      * this is done by the time it returns from {@link #finishUpdate(android.view.ViewGroup)}.
117      *
118      * @param container The containing View from which the page will be removed.
119      * @param position The page position to be removed.
120      * @param object The same object that was returned by
121      * {@link #instantiateItem(android.view.View, int)}.
122      */
destroyItem(ViewGroup container, int position, Object object)123     public void destroyItem(ViewGroup container, int position, Object object) {
124         destroyItem((View) container, position, object);
125     }
126 
127     /**
128      * Called to inform the adapter of which item is currently considered to
129      * be the "primary", that is the one show to the user as the current page.
130      *
131      * @param container The containing View from which the page will be removed.
132      * @param position The page position that is now the primary.
133      * @param object The same object that was returned by
134      * {@link #instantiateItem(android.view.View, int)}.
135      */
setPrimaryItem(ViewGroup container, int position, Object object)136     public void setPrimaryItem(ViewGroup container, int position, Object object) {
137         setPrimaryItem((View) container, position, object);
138     }
139 
140     /**
141      * Called when the a change in the shown pages has been completed.  At this
142      * point you must ensure that all of the pages have actually been added or
143      * removed from the container as appropriate.
144      * @param container The containing View which is displaying this adapter's
145      * page views.
146      */
finishUpdate(ViewGroup container)147     public void finishUpdate(ViewGroup container) {
148         finishUpdate((View) container);
149     }
150 
151     /**
152      * Called when a change in the shown pages is going to start being made.
153      * @param container The containing View which is displaying this adapter's
154      * page views.
155      *
156      * @deprecated Use {@link #startUpdate(android.view.ViewGroup)}
157      */
startUpdate(View container)158     public void startUpdate(View container) {
159     }
160 
161     /**
162      * Create the page for the given position.  The adapter is responsible
163      * for adding the view to the container given here, although it only
164      * must ensure this is done by the time it returns from
165      * {@link #finishUpdate(android.view.ViewGroup)}.
166      *
167      * @param container The containing View in which the page will be shown.
168      * @param position The page position to be instantiated.
169      * @return Returns an Object representing the new page.  This does not
170      * need to be a View, but can be some other container of the page.
171      *
172      * @deprecated Use {@link #instantiateItem(android.view.ViewGroup, int)}
173      */
instantiateItem(View container, int position)174     public Object instantiateItem(View container, int position) {
175         throw new UnsupportedOperationException(
176                 "Required method instantiateItem was not overridden");
177     }
178 
179     /**
180      * Remove a page for the given position.  The adapter is responsible
181      * for removing the view from its container, although it only must ensure
182      * this is done by the time it returns from {@link #finishUpdate(android.view.View)}.
183      *
184      * @param container The containing View from which the page will be removed.
185      * @param position The page position to be removed.
186      * @param object The same object that was returned by
187      * {@link #instantiateItem(android.view.View, int)}.
188      *
189      * @deprecated Use {@link #destroyItem(android.view.ViewGroup, int, Object)}
190      */
destroyItem(View container, int position, Object object)191     public void destroyItem(View container, int position, Object object) {
192         throw new UnsupportedOperationException("Required method destroyItem was not overridden");
193     }
194 
195     /**
196      * Called to inform the adapter of which item is currently considered to
197      * be the "primary", that is the one show to the user as the current page.
198      *
199      * @param container The containing View from which the page will be removed.
200      * @param position The page position that is now the primary.
201      * @param object The same object that was returned by
202      * {@link #instantiateItem(android.view.View, int)}.
203      *
204      * @deprecated Use {@link #setPrimaryItem(android.view.ViewGroup, int, Object)}
205      */
setPrimaryItem(View container, int position, Object object)206     public void setPrimaryItem(View container, int position, Object object) {
207     }
208 
209     /**
210      * Called when the a change in the shown pages has been completed.  At this
211      * point you must ensure that all of the pages have actually been added or
212      * removed from the container as appropriate.
213      * @param container The containing View which is displaying this adapter's
214      * page views.
215      *
216      * @deprecated Use {@link #finishUpdate(android.view.ViewGroup)}
217      */
finishUpdate(View container)218     public void finishUpdate(View container) {
219     }
220 
221     /**
222      * Determines whether a page View is associated with a specific key object
223      * as returned by {@link #instantiateItem(android.view.ViewGroup, int)}. This method is
224      * required for a PagerAdapter to function properly.
225      *
226      * @param view Page View to check for association with <code>object</code>
227      * @param object Object to check for association with <code>view</code>
228      * @return true if <code>view</code> is associated with the key object <code>object</code>
229      */
isViewFromObject(View view, Object object)230     public abstract boolean isViewFromObject(View view, Object object);
231 
232     /**
233      * Save any instance state associated with this adapter and its pages that should be
234      * restored if the current UI state needs to be reconstructed.
235      *
236      * @return Saved state for this adapter
237      */
saveState()238     public Parcelable saveState() {
239         return null;
240     }
241 
242     /**
243      * Restore any instance state associated with this adapter and its pages
244      * that was previously saved by {@link #saveState()}.
245      *
246      * @param state State previously saved by a call to {@link #saveState()}
247      * @param loader A ClassLoader that should be used to instantiate any restored objects
248      */
restoreState(Parcelable state, ClassLoader loader)249     public void restoreState(Parcelable state, ClassLoader loader) {
250     }
251 
252     /**
253      * Called when the host view is attempting to determine if an item's position
254      * has changed. Returns {@link #POSITION_UNCHANGED} if the position of the given
255      * item has not changed or {@link #POSITION_NONE} if the item is no longer present
256      * in the adapter.
257      *
258      * <p>The default implementation assumes that items will never
259      * change position and always returns {@link #POSITION_UNCHANGED}.
260      *
261      * @param object Object representing an item, previously returned by a call to
262      *               {@link #instantiateItem(android.view.View, int)}.
263      * @return object's new position index from [0, {@link #getCount()}),
264      *         {@link #POSITION_UNCHANGED} if the object's position has not changed,
265      *         or {@link #POSITION_NONE} if the item is no longer present.
266      */
getItemPosition(Object object)267     public int getItemPosition(Object object) {
268         return POSITION_UNCHANGED;
269     }
270 
271     /**
272      * This method should be called by the application if the data backing this adapter has changed
273      * and associated views should update.
274      */
notifyDataSetChanged()275     public void notifyDataSetChanged() {
276         mObservable.notifyChanged();
277     }
278 
279     /**
280      * Register an observer to receive callbacks related to the adapter's data changing.
281      *
282      * @param observer The {@link android.database.DataSetObserver} which will receive callbacks.
283      */
registerDataSetObserver(DataSetObserver observer)284     public void registerDataSetObserver(DataSetObserver observer) {
285         mObservable.registerObserver(observer);
286     }
287 
288     /**
289      * Unregister an observer from callbacks related to the adapter's data changing.
290      *
291      * @param observer The {@link android.database.DataSetObserver} which will be unregistered.
292      */
unregisterDataSetObserver(DataSetObserver observer)293     public void unregisterDataSetObserver(DataSetObserver observer) {
294         mObservable.unregisterObserver(observer);
295     }
296 
297     /**
298      * This method may be called by the ViewPager to obtain a title string
299      * to describe the specified page. This method may return null
300      * indicating no title for this page. The default implementation returns
301      * null.
302      *
303      * @param position The position of the title requested
304      * @return A title for the requested page
305      */
getPageTitle(int position)306     public CharSequence getPageTitle(int position) {
307         return null;
308     }
309 
310     /**
311      * Returns the proportional width of a given page as a percentage of the
312      * ViewPager's measured width from (0.f-1.f]
313      *
314      * @param position The position of the page requested
315      * @return Proportional width for the given page position
316      */
getPageWidth(int position)317     public float getPageWidth(int position) {
318         return 1.f;
319     }
320 }
321