Last active
August 29, 2015 14:19
-
-
Save saguinav/de660c8654f5a361fbf2 to your computer and use it in GitHub Desktop.
This class aims to provide a base implementation for PagerAdapter that includes a mechanism for recycling views.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2015 Samuel Guirado Navarro | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
import android.support.v4.view.PagerAdapter; | |
import android.util.SparseArray; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import com.groupon.commonlibs.R; | |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* This class aims to provide a base implementation for | |
* PagerAdapter that includes a mechanism for recycling views. | |
* | |
* NOTE: This implementation uses a ViewHolder pattern | |
* as a key component of the recycling mechanism. | |
* That viewholder instance is saved in the view as a | |
* tag object with a unique key: | |
* | |
* view.setTag(TAG_KEY, tag) | |
*/ | |
public abstract class RecyclerPagerAdapter extends PagerAdapter { | |
private static final int TAG_KEY = R.id.RECYCLER_PAGER_ADAPTER_TAG_KEY; | |
private static class InternalItem { | |
public Object instantiatedObject; | |
public int viewType; | |
public int position; | |
public float pageWidth; | |
} | |
final List<InternalItem> instantiatedItems = new ArrayList<InternalItem>(); | |
final List<InternalItem> destroyedItems = new ArrayList<InternalItem>(); | |
@Override | |
public final void startUpdate(ViewGroup container) { | |
clearItems(); | |
} | |
@Override | |
public final Object instantiateItem(ViewGroup container, int position) { | |
final InternalItem item = new InternalItem(); | |
item.instantiatedObject = getItem(position); | |
item.position = position; | |
item.viewType = getItemViewType(position); | |
item.pageWidth = getPageWidth(position); | |
instantiatedItems.add(item); | |
return item; | |
} | |
@Override | |
public final void destroyItem(ViewGroup container, int position, Object object) { | |
destroyedItems.add((InternalItem) object); | |
} | |
@Override | |
public final void finishUpdate(ViewGroup container) { | |
final SparseArrayCompat<List<View>> viewsToRecycle = removeDestroyedItemsViews(container); | |
// Render views and attach them to the container. Page views are reused | |
// whenever possible. | |
for (InternalItem instantiatedItem : instantiatedItems) { | |
List<View> views = null; | |
if (viewsToRecycle.size() > 0) { | |
views = viewsToRecycle.get(instantiatedItem.viewType); | |
} | |
final View convertView; | |
if (views != null && views.size() > 0) { | |
convertView = views.remove(0); | |
// Re-add existing view before rendering so that we can make change inside getView() | |
container.addView(convertView); | |
getView(instantiatedItem.position, | |
convertView, | |
container); | |
} else { | |
convertView = getView(instantiatedItem.position, | |
null, | |
container); | |
container.addView(convertView); | |
} | |
convertView.setTag(TAG_KEY, instantiatedItem); | |
} | |
clearItems(); | |
} | |
@Override | |
public final boolean isViewFromObject(View view, Object object) { | |
return getInternalItem(view) == object; | |
} | |
@Override | |
public final int getItemPosition(Object object) { | |
final InternalItem item = (InternalItem) object; | |
if (item.instantiatedObject.equals(getItem(item.position)) && | |
item.viewType == getItemViewType(item.position) && | |
item.pageWidth == getPageWidth(item.position)) { | |
return item.position; | |
} else { | |
return POSITION_NONE; | |
} | |
} | |
/** | |
* Get the data item associated with the specified position in the data set. | |
* | |
* @param position | |
* Position of the item whose data we want within the adapter's data set. | |
* @return The data at the specified position. | |
* The object must override the {@link Object#equals(Object)} method in order to | |
* allow comparison between objects. | |
*/ | |
public abstract Object getItem(int position); | |
/** | |
* Get a View that displays the data at the specified position in the data set. | |
* | |
* @param position | |
* The position of the item | |
* @param convertView | |
* The view to be reused. | |
* @param parent | |
* The parent that this view will eventually be attached to. | |
* @return A View corresponding to the data at the specified position. | |
*/ | |
public abstract View getView(int position, View convertView, ViewGroup parent); | |
public int getItemViewType(int position) { | |
return 0; | |
} | |
/** | |
* Remove views backing destroyed items from the specified container | |
* @param container The container that contains the views | |
* @return The views from destroyed items that have been removed from the specified container | |
*/ | |
private SparseArrayCompat<List<View>> removeDestroyedItemsViews(ViewGroup container) { | |
final List<View> viewsToRemove = new ArrayList<View>(); | |
// The key of this SparseArray will be the ViewType | |
final SparseArrayCompat<List<View>> removedViews = new SparseArrayCompat<List<View>>(); | |
for (int i=0; i<container.getChildCount(); ++i) { | |
final View view = container.getChildAt(i); | |
final InternalItem item = getInternalItem(view); | |
if (destroyedItems.indexOf(item) >= 0) { | |
viewsToRemove.add(view); | |
List<View> views = removedViews.get(item.viewType); | |
if (views == null) { | |
views = new ArrayList<View>(); | |
removedViews.put(item.viewType, views); | |
} | |
views.add(view); | |
} | |
} | |
for (View view : viewsToRemove) { | |
container.removeView(view); | |
} | |
return removedViews; | |
} | |
/** | |
* Clears all the items stored | |
*/ | |
private void clearItems() { | |
instantiatedItems.clear(); | |
destroyedItems.clear(); | |
} | |
private static InternalItem getInternalItem(View view) { | |
return (InternalItem) view.getTag(TAG_KEY); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment