diff options
Diffstat (limited to 'src/com/android/photos/views/GalleryThumbnailView.java')
-rw-r--r-- | src/com/android/photos/views/GalleryThumbnailView.java | 883 |
1 files changed, 0 insertions, 883 deletions
diff --git a/src/com/android/photos/views/GalleryThumbnailView.java b/src/com/android/photos/views/GalleryThumbnailView.java deleted file mode 100644 index e5dd6f2ff..000000000 --- a/src/com/android/photos/views/GalleryThumbnailView.java +++ /dev/null @@ -1,883 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -package com.android.photos.views; - -import android.content.Context; -import android.content.res.TypedArray; -import android.database.DataSetObserver; -import android.graphics.Canvas; -import android.support.v4.view.MotionEventCompat; -import android.support.v4.view.VelocityTrackerCompat; -import android.support.v4.view.ViewCompat; -import android.support.v4.widget.EdgeEffectCompat; -import android.util.AttributeSet; -import android.util.Log; -import android.util.SparseArray; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.widget.ListAdapter; -import android.widget.OverScroller; - -import java.util.ArrayList; - -public class GalleryThumbnailView extends ViewGroup { - - public interface GalleryThumbnailAdapter extends ListAdapter { - /** - * @param position Position to get the intrinsic aspect ratio for - * @return width / height - */ - float getIntrinsicAspectRatio(int position); - } - - private static final String TAG = "GalleryThumbnailView"; - private static final float ASPECT_RATIO = (float) Math.sqrt(1.5f); - private static final int LAND_UNITS = 2; - private static final int PORT_UNITS = 3; - - private GalleryThumbnailAdapter mAdapter; - - private final RecycleBin mRecycler = new RecycleBin(); - - private final AdapterDataSetObserver mObserver = new AdapterDataSetObserver(); - - private boolean mDataChanged; - private int mOldItemCount; - private int mItemCount; - private boolean mHasStableIds; - - private int mFirstPosition; - - private boolean mPopulating; - private boolean mInLayout; - - private int mTouchSlop; - private int mMaximumVelocity; - private int mFlingVelocity; - private float mLastTouchX; - private float mTouchRemainderX; - private int mActivePointerId; - - private static final int TOUCH_MODE_IDLE = 0; - private static final int TOUCH_MODE_DRAGGING = 1; - private static final int TOUCH_MODE_FLINGING = 2; - - private int mTouchMode; - private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); - private final OverScroller mScroller; - - private final EdgeEffectCompat mLeftEdge; - private final EdgeEffectCompat mRightEdge; - - private int mLargeColumnWidth; - private int mSmallColumnWidth; - private int mLargeColumnUnitCount = 8; - private int mSmallColumnUnitCount = 10; - - public GalleryThumbnailView(Context context) { - this(context, null); - } - - public GalleryThumbnailView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public GalleryThumbnailView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - final ViewConfiguration vc = ViewConfiguration.get(context); - mTouchSlop = vc.getScaledTouchSlop(); - mMaximumVelocity = vc.getScaledMaximumFlingVelocity(); - mFlingVelocity = vc.getScaledMinimumFlingVelocity(); - mScroller = new OverScroller(context); - - mLeftEdge = new EdgeEffectCompat(context); - mRightEdge = new EdgeEffectCompat(context); - setWillNotDraw(false); - setClipToPadding(false); - } - - @Override - public void requestLayout() { - if (!mPopulating) { - super.requestLayout(); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - if (widthMode != MeasureSpec.EXACTLY) { - Log.e(TAG, "onMeasure: must have an exact width or match_parent! " + - "Using fallback spec of EXACTLY " + widthSize); - } - if (heightMode != MeasureSpec.EXACTLY) { - Log.e(TAG, "onMeasure: must have an exact height or match_parent! " + - "Using fallback spec of EXACTLY " + heightSize); - } - - setMeasuredDimension(widthSize, heightSize); - - float portSpaces = mLargeColumnUnitCount / PORT_UNITS; - float height = getMeasuredHeight() / portSpaces; - mLargeColumnWidth = (int) (height / ASPECT_RATIO); - portSpaces++; - height = getMeasuredHeight() / portSpaces; - mSmallColumnWidth = (int) (height / ASPECT_RATIO); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - mInLayout = true; - populate(); - mInLayout = false; - - final int width = r - l; - final int height = b - t; - mLeftEdge.setSize(width, height); - mRightEdge.setSize(width, height); - } - - private void populate() { - if (getWidth() == 0 || getHeight() == 0) { - return; - } - - // TODO: Handle size changing -// final int colCount = mColCount; -// if (mItemTops == null || mItemTops.length != colCount) { -// mItemTops = new int[colCount]; -// mItemBottoms = new int[colCount]; -// final int top = getPaddingTop(); -// final int offset = top + Math.min(mRestoreOffset, 0); -// Arrays.fill(mItemTops, offset); -// Arrays.fill(mItemBottoms, offset); -// mLayoutRecords.clear(); -// if (mInLayout) { -// removeAllViewsInLayout(); -// } else { -// removeAllViews(); -// } -// mRestoreOffset = 0; -// } - - mPopulating = true; - layoutChildren(mDataChanged); - fillRight(mFirstPosition + getChildCount(), 0); - fillLeft(mFirstPosition - 1, 0); - mPopulating = false; - mDataChanged = false; - } - - final void layoutChildren(boolean queryAdapter) { -// TODO -// final int childCount = getChildCount(); -// for (int i = 0; i < childCount; i++) { -// View child = getChildAt(i); -// -// if (child.isLayoutRequested()) { -// final int widthSpec = MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(), MeasureSpec.EXACTLY); -// final int heightSpec = MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY); -// child.measure(widthSpec, heightSpec); -// child.layout(child.getLeft(), child.getTop(), child.getRight(), child.getBottom()); -// } -// -// int childTop = mItemBottoms[col] > Integer.MIN_VALUE ? -// mItemBottoms[col] + mItemMargin : child.getTop(); -// if (span > 1) { -// int lowest = childTop; -// for (int j = col + 1; j < col + span; j++) { -// final int bottom = mItemBottoms[j] + mItemMargin; -// if (bottom > lowest) { -// lowest = bottom; -// } -// } -// childTop = lowest; -// } -// final int childHeight = child.getMeasuredHeight(); -// final int childBottom = childTop + childHeight; -// final int childLeft = paddingLeft + col * (colWidth + itemMargin); -// final int childRight = childLeft + child.getMeasuredWidth(); -// child.layout(childLeft, childTop, childRight, childBottom); -// } - } - - /** - * Obtain the view and add it to our list of children. The view can be made - * fresh, converted from an unused view, or used as is if it was in the - * recycle bin. - * - * @param startPosition Logical position in the list to start from - * @param x Left or right edge of the view to add - * @param forward If true, align left edge to x and increase position. - * If false, align right edge to x and decrease position. - * @return Number of views added - */ - private int makeAndAddColumn(int startPosition, int x, boolean forward) { - int columnWidth = mLargeColumnWidth; - int addViews = 0; - for (int remaining = mLargeColumnUnitCount, i = 0; - remaining > 0 && startPosition + i >= 0 && startPosition + i < mItemCount; - i += forward ? 1 : -1, addViews++) { - if (mAdapter.getIntrinsicAspectRatio(startPosition + i) >= 1f) { - // landscape - remaining -= LAND_UNITS; - } else { - // portrait - remaining -= PORT_UNITS; - if (remaining < 0) { - remaining += (mSmallColumnUnitCount - mLargeColumnUnitCount); - columnWidth = mSmallColumnWidth; - } - } - } - int nextTop = 0; - for (int i = 0; i < addViews; i++) { - int position = startPosition + (forward ? i : -i); - View child = obtainView(position, null); - if (child.getParent() != this) { - if (mInLayout) { - addViewInLayout(child, forward ? -1 : 0, child.getLayoutParams()); - } else { - addView(child, forward ? -1 : 0); - } - } - int heightSize = (int) (.5f + (mAdapter.getIntrinsicAspectRatio(position) >= 1f - ? columnWidth / ASPECT_RATIO - : columnWidth * ASPECT_RATIO)); - int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY); - int widthSpec = MeasureSpec.makeMeasureSpec(columnWidth, MeasureSpec.EXACTLY); - child.measure(widthSpec, heightSpec); - int childLeft = forward ? x : x - columnWidth; - child.layout(childLeft, nextTop, childLeft + columnWidth, nextTop + heightSize); - nextTop += heightSize; - } - return addViews; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - mVelocityTracker.addMovement(ev); - final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; - switch (action) { - case MotionEvent.ACTION_DOWN: - mVelocityTracker.clear(); - mScroller.abortAnimation(); - mLastTouchX = ev.getX(); - mActivePointerId = MotionEventCompat.getPointerId(ev, 0); - mTouchRemainderX = 0; - if (mTouchMode == TOUCH_MODE_FLINGING) { - // Catch! - mTouchMode = TOUCH_MODE_DRAGGING; - return true; - } - break; - - case MotionEvent.ACTION_MOVE: { - final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId); - if (index < 0) { - Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " + - mActivePointerId + " - did StaggeredGridView receive an inconsistent " + - "event stream?"); - return false; - } - final float x = MotionEventCompat.getX(ev, index); - final float dx = x - mLastTouchX + mTouchRemainderX; - final int deltaY = (int) dx; - mTouchRemainderX = dx - deltaY; - - if (Math.abs(dx) > mTouchSlop) { - mTouchMode = TOUCH_MODE_DRAGGING; - return true; - } - } - } - - return false; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - mVelocityTracker.addMovement(ev); - final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; - switch (action) { - case MotionEvent.ACTION_DOWN: - mVelocityTracker.clear(); - mScroller.abortAnimation(); - mLastTouchX = ev.getX(); - mActivePointerId = MotionEventCompat.getPointerId(ev, 0); - mTouchRemainderX = 0; - break; - - case MotionEvent.ACTION_MOVE: { - final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId); - if (index < 0) { - Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " + - mActivePointerId + " - did StaggeredGridView receive an inconsistent " + - "event stream?"); - return false; - } - final float x = MotionEventCompat.getX(ev, index); - final float dx = x - mLastTouchX + mTouchRemainderX; - final int deltaX = (int) dx; - mTouchRemainderX = dx - deltaX; - - if (Math.abs(dx) > mTouchSlop) { - mTouchMode = TOUCH_MODE_DRAGGING; - } - - if (mTouchMode == TOUCH_MODE_DRAGGING) { - mLastTouchX = x; - - if (!trackMotionScroll(deltaX, true)) { - // Break fling velocity if we impacted an edge. - mVelocityTracker.clear(); - } - } - } break; - - case MotionEvent.ACTION_CANCEL: - mTouchMode = TOUCH_MODE_IDLE; - break; - - case MotionEvent.ACTION_UP: { - mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); - final float velocity = VelocityTrackerCompat.getXVelocity(mVelocityTracker, - mActivePointerId); - if (Math.abs(velocity) > mFlingVelocity) { // TODO - mTouchMode = TOUCH_MODE_FLINGING; - mScroller.fling(0, 0, (int) velocity, 0, - Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0); - mLastTouchX = 0; - ViewCompat.postInvalidateOnAnimation(this); - } else { - mTouchMode = TOUCH_MODE_IDLE; - } - - } break; - } - return true; - } - - /** - * - * @param deltaX Pixels that content should move by - * @return true if the movement completed, false if it was stopped prematurely. - */ - private boolean trackMotionScroll(int deltaX, boolean allowOverScroll) { - final boolean contentFits = contentFits(); - final int allowOverhang = Math.abs(deltaX); - - final int overScrolledBy; - final int movedBy; - if (!contentFits) { - final int overhang; - final boolean up; - mPopulating = true; - if (deltaX > 0) { - overhang = fillLeft(mFirstPosition - 1, allowOverhang); - up = true; - } else { - overhang = fillRight(mFirstPosition + getChildCount(), allowOverhang); - up = false; - } - movedBy = Math.min(overhang, allowOverhang); - offsetChildren(up ? movedBy : -movedBy); - recycleOffscreenViews(); - mPopulating = false; - overScrolledBy = allowOverhang - overhang; - } else { - overScrolledBy = allowOverhang; - movedBy = 0; - } - - if (allowOverScroll) { - final int overScrollMode = ViewCompat.getOverScrollMode(this); - - if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || - (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits)) { - - if (overScrolledBy > 0) { - EdgeEffectCompat edge = deltaX > 0 ? mLeftEdge : mRightEdge; - edge.onPull((float) Math.abs(deltaX) / getWidth()); - ViewCompat.postInvalidateOnAnimation(this); - } - } - } - - return deltaX == 0 || movedBy != 0; - } - - /** - * Important: this method will leave offscreen views attached if they - * are required to maintain the invariant that child view with index i - * is always the view corresponding to position mFirstPosition + i. - */ - private void recycleOffscreenViews() { - final int height = getHeight(); - final int clearAbove = 0; - final int clearBelow = height; - for (int i = getChildCount() - 1; i >= 0; i--) { - final View child = getChildAt(i); - if (child.getTop() <= clearBelow) { - // There may be other offscreen views, but we need to maintain - // the invariant documented above. - break; - } - - if (mInLayout) { - removeViewsInLayout(i, 1); - } else { - removeViewAt(i); - } - - mRecycler.addScrap(child); - } - - while (getChildCount() > 0) { - final View child = getChildAt(0); - if (child.getBottom() >= clearAbove) { - // There may be other offscreen views, but we need to maintain - // the invariant documented above. - break; - } - - if (mInLayout) { - removeViewsInLayout(0, 1); - } else { - removeViewAt(0); - } - - mRecycler.addScrap(child); - mFirstPosition++; - } - } - - final void offsetChildren(int offset) { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - child.layout(child.getLeft() + offset, child.getTop(), - child.getRight() + offset, child.getBottom()); - } - } - - private boolean contentFits() { - final int childCount = getChildCount(); - if (childCount == 0) return true; - if (childCount != mItemCount) return false; - - return getChildAt(0).getLeft() >= getPaddingLeft() && - getChildAt(childCount - 1).getRight() <= getWidth() - getPaddingRight(); - } - - private void recycleAllViews() { - for (int i = 0; i < getChildCount(); i++) { - mRecycler.addScrap(getChildAt(i)); - } - - if (mInLayout) { - removeAllViewsInLayout(); - } else { - removeAllViews(); - } - } - - private int fillRight(int pos, int overhang) { - int end = (getRight() - getLeft()) + overhang; - - int nextLeft = getChildCount() == 0 ? 0 : getChildAt(getChildCount() - 1).getRight(); - while (nextLeft < end && pos < mItemCount) { - pos += makeAndAddColumn(pos, nextLeft, true); - nextLeft = getChildAt(getChildCount() - 1).getRight(); - } - final int gridRight = getWidth() - getPaddingRight(); - return getChildAt(getChildCount() - 1).getRight() - gridRight; - } - - private int fillLeft(int pos, int overhang) { - int end = getPaddingLeft() - overhang; - - int nextRight = getChildAt(0).getLeft(); - while (nextRight > end && pos >= 0) { - pos -= makeAndAddColumn(pos, nextRight, false); - nextRight = getChildAt(0).getLeft(); - } - - mFirstPosition = pos + 1; - return getPaddingLeft() - getChildAt(0).getLeft(); - } - - @Override - public void computeScroll() { - if (mScroller.computeScrollOffset()) { - final int x = mScroller.getCurrX(); - final int dx = (int) (x - mLastTouchX); - mLastTouchX = x; - final boolean stopped = !trackMotionScroll(dx, false); - - if (!stopped && !mScroller.isFinished()) { - ViewCompat.postInvalidateOnAnimation(this); - } else { - if (stopped) { - final int overScrollMode = ViewCompat.getOverScrollMode(this); - if (overScrollMode != ViewCompat.OVER_SCROLL_NEVER) { - final EdgeEffectCompat edge; - if (dx > 0) { - edge = mLeftEdge; - } else { - edge = mRightEdge; - } - edge.onAbsorb(Math.abs((int) mScroller.getCurrVelocity())); - ViewCompat.postInvalidateOnAnimation(this); - } - mScroller.abortAnimation(); - } - mTouchMode = TOUCH_MODE_IDLE; - } - } - } - - @Override - public void draw(Canvas canvas) { - super.draw(canvas); - - if (!mLeftEdge.isFinished()) { - final int restoreCount = canvas.save(); - final int height = getHeight() - getPaddingTop() - getPaddingBottom(); - - canvas.rotate(270); - canvas.translate(-height + getPaddingTop(), 0); - mLeftEdge.setSize(height, getWidth()); - if (mLeftEdge.draw(canvas)) { - postInvalidateOnAnimation(); - } - canvas.restoreToCount(restoreCount); - } - if (!mRightEdge.isFinished()) { - final int restoreCount = canvas.save(); - final int width = getWidth(); - final int height = getHeight() - getPaddingTop() - getPaddingBottom(); - - canvas.rotate(90); - canvas.translate(-getPaddingTop(), width); - mRightEdge.setSize(height, width); - if (mRightEdge.draw(canvas)) { - postInvalidateOnAnimation(); - } - canvas.restoreToCount(restoreCount); - } - } - - /** - * Obtain a populated view from the adapter. If optScrap is non-null and is not - * reused it will be placed in the recycle bin. - * - * @param position position to get view for - * @param optScrap Optional scrap view; will be reused if possible - * @return A new view, a recycled view from mRecycler, or optScrap - */ - private final View obtainView(int position, View optScrap) { - View view = mRecycler.getTransientStateView(position); - if (view != null) { - return view; - } - - // Reuse optScrap if it's of the right type (and not null) - final int optType = optScrap != null ? - ((LayoutParams) optScrap.getLayoutParams()).viewType : -1; - final int positionViewType = mAdapter.getItemViewType(position); - final View scrap = optType == positionViewType ? - optScrap : mRecycler.getScrapView(positionViewType); - - view = mAdapter.getView(position, scrap, this); - - if (view != scrap && scrap != null) { - // The adapter didn't use it; put it back. - mRecycler.addScrap(scrap); - } - - ViewGroup.LayoutParams lp = view.getLayoutParams(); - - if (view.getParent() != this) { - if (lp == null) { - lp = generateDefaultLayoutParams(); - } else if (!checkLayoutParams(lp)) { - lp = generateLayoutParams(lp); - } - view.setLayoutParams(lp); - } - - final LayoutParams sglp = (LayoutParams) lp; - sglp.position = position; - sglp.viewType = positionViewType; - - return view; - } - - public GalleryThumbnailAdapter getAdapter() { - return mAdapter; - } - - public void setAdapter(GalleryThumbnailAdapter adapter) { - if (mAdapter != null) { - mAdapter.unregisterDataSetObserver(mObserver); - } - // TODO: If the new adapter says that there are stable IDs, remove certain layout records - // and onscreen views if they have changed instead of removing all of the state here. - clearAllState(); - mAdapter = adapter; - mDataChanged = true; - mOldItemCount = mItemCount = adapter != null ? adapter.getCount() : 0; - if (adapter != null) { - adapter.registerDataSetObserver(mObserver); - mRecycler.setViewTypeCount(adapter.getViewTypeCount()); - mHasStableIds = adapter.hasStableIds(); - } else { - mHasStableIds = false; - } - populate(); - } - - /** - * Clear all state because the grid will be used for a completely different set of data. - */ - private void clearAllState() { - // Clear all layout records and views - removeAllViews(); - - // Reset to the top of the grid - mFirstPosition = 0; - - // Clear recycler because there could be different view types now - mRecycler.clear(); - } - - @Override - protected LayoutParams generateDefaultLayoutParams() { - return new LayoutParams(LayoutParams.WRAP_CONTENT); - } - - @Override - protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { - return new LayoutParams(lp); - } - - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams lp) { - return lp instanceof LayoutParams; - } - - @Override - public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { - return new LayoutParams(getContext(), attrs); - } - - public static class LayoutParams extends ViewGroup.LayoutParams { - private static final int[] LAYOUT_ATTRS = new int[] { - android.R.attr.layout_span - }; - - private static final int SPAN_INDEX = 0; - - /** - * The number of columns this item should span - */ - public int span = 1; - - /** - * Item position this view represents - */ - int position; - - /** - * Type of this view as reported by the adapter - */ - int viewType; - - /** - * The column this view is occupying - */ - int column; - - /** - * The stable ID of the item this view displays - */ - long id = -1; - - public LayoutParams(int height) { - super(MATCH_PARENT, height); - - if (this.height == MATCH_PARENT) { - Log.w(TAG, "Constructing LayoutParams with height MATCH_PARENT - " + - "impossible! Falling back to WRAP_CONTENT"); - this.height = WRAP_CONTENT; - } - } - - public LayoutParams(Context c, AttributeSet attrs) { - super(c, attrs); - - if (this.width != MATCH_PARENT) { - Log.w(TAG, "Inflation setting LayoutParams width to " + this.width + - " - must be MATCH_PARENT"); - this.width = MATCH_PARENT; - } - if (this.height == MATCH_PARENT) { - Log.w(TAG, "Inflation setting LayoutParams height to MATCH_PARENT - " + - "impossible! Falling back to WRAP_CONTENT"); - this.height = WRAP_CONTENT; - } - - TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS); - span = a.getInteger(SPAN_INDEX, 1); - a.recycle(); - } - - public LayoutParams(ViewGroup.LayoutParams other) { - super(other); - - if (this.width != MATCH_PARENT) { - Log.w(TAG, "Constructing LayoutParams with width " + this.width + - " - must be MATCH_PARENT"); - this.width = MATCH_PARENT; - } - if (this.height == MATCH_PARENT) { - Log.w(TAG, "Constructing LayoutParams with height MATCH_PARENT - " + - "impossible! Falling back to WRAP_CONTENT"); - this.height = WRAP_CONTENT; - } - } - } - - private class RecycleBin { - private ArrayList<View>[] mScrapViews; - private int mViewTypeCount; - private int mMaxScrap; - - private SparseArray<View> mTransientStateViews; - - public void setViewTypeCount(int viewTypeCount) { - if (viewTypeCount < 1) { - throw new IllegalArgumentException("Must have at least one view type (" + - viewTypeCount + " types reported)"); - } - if (viewTypeCount == mViewTypeCount) { - return; - } - - ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount]; - for (int i = 0; i < viewTypeCount; i++) { - scrapViews[i] = new ArrayList<View>(); - } - mViewTypeCount = viewTypeCount; - mScrapViews = scrapViews; - } - - public void clear() { - final int typeCount = mViewTypeCount; - for (int i = 0; i < typeCount; i++) { - mScrapViews[i].clear(); - } - if (mTransientStateViews != null) { - mTransientStateViews.clear(); - } - } - - public void clearTransientViews() { - if (mTransientStateViews != null) { - mTransientStateViews.clear(); - } - } - - public void addScrap(View v) { - final LayoutParams lp = (LayoutParams) v.getLayoutParams(); - if (ViewCompat.hasTransientState(v)) { - if (mTransientStateViews == null) { - mTransientStateViews = new SparseArray<View>(); - } - mTransientStateViews.put(lp.position, v); - return; - } - - final int childCount = getChildCount(); - if (childCount > mMaxScrap) { - mMaxScrap = childCount; - } - - ArrayList<View> scrap = mScrapViews[lp.viewType]; - if (scrap.size() < mMaxScrap) { - scrap.add(v); - } - } - - public View getTransientStateView(int position) { - if (mTransientStateViews == null) { - return null; - } - - final View result = mTransientStateViews.get(position); - if (result != null) { - mTransientStateViews.remove(position); - } - return result; - } - - public View getScrapView(int type) { - ArrayList<View> scrap = mScrapViews[type]; - if (scrap.isEmpty()) { - return null; - } - - final int index = scrap.size() - 1; - final View result = scrap.get(index); - scrap.remove(index); - return result; - } - } - - private class AdapterDataSetObserver extends DataSetObserver { - @Override - public void onChanged() { - mDataChanged = true; - mOldItemCount = mItemCount; - mItemCount = mAdapter.getCount(); - - // TODO: Consider matching these back up if we have stable IDs. - mRecycler.clearTransientViews(); - - if (!mHasStableIds) { - recycleAllViews(); - } - - // TODO: consider repopulating in a deferred runnable instead - // (so that successive changes may still be batched) - requestLayout(); - } - - @Override - public void onInvalidated() { - } - } -} |