1/* 2 * Copyright (C) 2011 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 17package android.support.v4.view; 18 19import android.database.DataSetObservable; 20import android.database.DataSetObserver; 21import android.os.Parcelable; 22import android.view.View; 23import android.view.ViewGroup; 24 25/** 26 * Base class providing the adapter to populate pages inside of 27 * a {@link 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(ViewGroup, int)}</li> 36 * <li>{@link #destroyItem(ViewGroup, int, Object)}</li> 37 * <li>{@link #getCount()}</li> 38 * <li>{@link #isViewFromObject(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(ViewGroup)} indicates that the contents of the ViewPager 53 * are about to change. One or more calls to {@link #instantiateItem(ViewGroup, int)} 54 * and/or {@link #destroyItem(ViewGroup, int, Object)} will follow, and the end 55 * of an update will be signaled by a call to {@link #finishUpdate(ViewGroup)}. 56 * By the time {@link #finishUpdate(ViewGroup) finishUpdate} returns the views 57 * associated with the key objects returned by 58 * {@link #instantiateItem(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(ViewGroup, int, Object) destroyItem} 61 * should be removed. The method {@link #isViewFromObject(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(ViewGroup, int)} 66 * after creation and adding them to the parent ViewGroup. A matching 67 * {@link #destroyItem(ViewGroup, int, Object)} implementation would remove the 68 * View from the parent ViewGroup and {@link #isViewFromObject(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 */ 78public abstract class PagerAdapter { 79 private final DataSetObservable mObservable = new DataSetObservable(); 80 private DataSetObserver mViewPagerObserver; 81 82 public static final int POSITION_UNCHANGED = -1; 83 public static final int POSITION_NONE = -2; 84 85 /** 86 * Return the number of views available. 87 */ 88 public abstract int getCount(); 89 90 /** 91 * Called when a change in the shown pages is going to start being made. 92 * @param container The containing View which is displaying this adapter's 93 * page views. 94 */ 95 public void startUpdate(ViewGroup container) { 96 startUpdate((View) container); 97 } 98 99 /** 100 * Create the page for the given position. The adapter is responsible 101 * for adding the view to the container given here, although it only 102 * must ensure this is done by the time it returns from 103 * {@link #finishUpdate(ViewGroup)}. 104 * 105 * @param container The containing View in which the page will be shown. 106 * @param position The page position to be instantiated. 107 * @return Returns an Object representing the new page. This does not 108 * need to be a View, but can be some other container of the page. 109 */ 110 public Object instantiateItem(ViewGroup container, int position) { 111 return instantiateItem((View) container, position); 112 } 113 114 /** 115 * Remove a page for the given position. The adapter is responsible 116 * for removing the view from its container, although it only must ensure 117 * this is done by the time it returns from {@link #finishUpdate(ViewGroup)}. 118 * 119 * @param container The containing View from which the page will be removed. 120 * @param position The page position to be removed. 121 * @param object The same object that was returned by 122 * {@link #instantiateItem(View, int)}. 123 */ 124 public void destroyItem(ViewGroup container, int position, Object object) { 125 destroyItem((View) container, position, object); 126 } 127 128 /** 129 * Called to inform the adapter of which item is currently considered to 130 * be the "primary", that is the one show to the user as the current page. 131 * 132 * @param container The containing View from which the page will be removed. 133 * @param position The page position that is now the primary. 134 * @param object The same object that was returned by 135 * {@link #instantiateItem(View, int)}. 136 */ 137 public void setPrimaryItem(ViewGroup container, int position, Object object) { 138 setPrimaryItem((View) container, position, object); 139 } 140 141 /** 142 * Called when the a change in the shown pages has been completed. At this 143 * point you must ensure that all of the pages have actually been added or 144 * removed from the container as appropriate. 145 * @param container The containing View which is displaying this adapter's 146 * page views. 147 */ 148 public void finishUpdate(ViewGroup container) { 149 finishUpdate((View) container); 150 } 151 152 /** 153 * Called when a change in the shown pages is going to start being made. 154 * @param container The containing View which is displaying this adapter's 155 * page views. 156 * 157 * @deprecated Use {@link #startUpdate(ViewGroup)} 158 */ 159 @Deprecated 160 public void startUpdate(View container) { 161 } 162 163 /** 164 * Create the page for the given position. The adapter is responsible 165 * for adding the view to the container given here, although it only 166 * must ensure this is done by the time it returns from 167 * {@link #finishUpdate(ViewGroup)}. 168 * 169 * @param container The containing View in which the page will be shown. 170 * @param position The page position to be instantiated. 171 * @return Returns an Object representing the new page. This does not 172 * need to be a View, but can be some other container of the page. 173 * 174 * @deprecated Use {@link #instantiateItem(ViewGroup, int)} 175 */ 176 @Deprecated 177 public Object instantiateItem(View container, int position) { 178 throw new UnsupportedOperationException( 179 "Required method instantiateItem was not overridden"); 180 } 181 182 /** 183 * Remove a page for the given position. The adapter is responsible 184 * for removing the view from its container, although it only must ensure 185 * this is done by the time it returns from {@link #finishUpdate(View)}. 186 * 187 * @param container The containing View from which the page will be removed. 188 * @param position The page position to be removed. 189 * @param object The same object that was returned by 190 * {@link #instantiateItem(View, int)}. 191 * 192 * @deprecated Use {@link #destroyItem(ViewGroup, int, Object)} 193 */ 194 @Deprecated 195 public void destroyItem(View container, int position, Object object) { 196 throw new UnsupportedOperationException("Required method destroyItem was not overridden"); 197 } 198 199 /** 200 * Called to inform the adapter of which item is currently considered to 201 * be the "primary", that is the one show to the user as the current page. 202 * 203 * @param container The containing View from which the page will be removed. 204 * @param position The page position that is now the primary. 205 * @param object The same object that was returned by 206 * {@link #instantiateItem(View, int)}. 207 * 208 * @deprecated Use {@link #setPrimaryItem(ViewGroup, int, Object)} 209 */ 210 @Deprecated 211 public void setPrimaryItem(View container, int position, Object object) { 212 } 213 214 /** 215 * Called when the a change in the shown pages has been completed. At this 216 * point you must ensure that all of the pages have actually been added or 217 * removed from the container as appropriate. 218 * @param container The containing View which is displaying this adapter's 219 * page views. 220 * 221 * @deprecated Use {@link #finishUpdate(ViewGroup)} 222 */ 223 @Deprecated 224 public void finishUpdate(View container) { 225 } 226 227 /** 228 * Determines whether a page View is associated with a specific key object 229 * as returned by {@link #instantiateItem(ViewGroup, int)}. This method is 230 * required for a PagerAdapter to function properly. 231 * 232 * @param view Page View to check for association with <code>object</code> 233 * @param object Object to check for association with <code>view</code> 234 * @return true if <code>view</code> is associated with the key object <code>object</code> 235 */ 236 public abstract boolean isViewFromObject(View view, Object object); 237 238 /** 239 * Save any instance state associated with this adapter and its pages that should be 240 * restored if the current UI state needs to be reconstructed. 241 * 242 * @return Saved state for this adapter 243 */ 244 public Parcelable saveState() { 245 return null; 246 } 247 248 /** 249 * Restore any instance state associated with this adapter and its pages 250 * that was previously saved by {@link #saveState()}. 251 * 252 * @param state State previously saved by a call to {@link #saveState()} 253 * @param loader A ClassLoader that should be used to instantiate any restored objects 254 */ 255 public void restoreState(Parcelable state, ClassLoader loader) { 256 } 257 258 /** 259 * Called when the host view is attempting to determine if an item's position 260 * has changed. Returns {@link #POSITION_UNCHANGED} if the position of the given 261 * item has not changed or {@link #POSITION_NONE} if the item is no longer present 262 * in the adapter. 263 * 264 * <p>The default implementation assumes that items will never 265 * change position and always returns {@link #POSITION_UNCHANGED}. 266 * 267 * @param object Object representing an item, previously returned by a call to 268 * {@link #instantiateItem(View, int)}. 269 * @return object's new position index from [0, {@link #getCount()}), 270 * {@link #POSITION_UNCHANGED} if the object's position has not changed, 271 * or {@link #POSITION_NONE} if the item is no longer present. 272 */ 273 public int getItemPosition(Object object) { 274 return POSITION_UNCHANGED; 275 } 276 277 /** 278 * This method should be called by the application if the data backing this adapter has changed 279 * and associated views should update. 280 */ 281 public void notifyDataSetChanged() { 282 synchronized (this) { 283 if (mViewPagerObserver != null) { 284 mViewPagerObserver.onChanged(); 285 } 286 } 287 mObservable.notifyChanged(); 288 } 289 290 /** 291 * Register an observer to receive callbacks related to the adapter's data changing. 292 * 293 * @param observer The {@link android.database.DataSetObserver} which will receive callbacks. 294 */ 295 public void registerDataSetObserver(DataSetObserver observer) { 296 mObservable.registerObserver(observer); 297 } 298 299 /** 300 * Unregister an observer from callbacks related to the adapter's data changing. 301 * 302 * @param observer The {@link android.database.DataSetObserver} which will be unregistered. 303 */ 304 public void unregisterDataSetObserver(DataSetObserver observer) { 305 mObservable.unregisterObserver(observer); 306 } 307 308 void setViewPagerObserver(DataSetObserver observer) { 309 synchronized (this) { 310 mViewPagerObserver = observer; 311 } 312 } 313 314 /** 315 * This method may be called by the ViewPager to obtain a title string 316 * to describe the specified page. This method may return null 317 * indicating no title for this page. The default implementation returns 318 * null. 319 * 320 * @param position The position of the title requested 321 * @return A title for the requested page 322 */ 323 public CharSequence getPageTitle(int position) { 324 return null; 325 } 326 327 /** 328 * Returns the proportional width of a given page as a percentage of the 329 * ViewPager's measured width from (0.f-1.f] 330 * 331 * @param position The position of the page requested 332 * @return Proportional width for the given page position 333 */ 334 public float getPageWidth(int position) { 335 return 1.f; 336 } 337} 338