Methods Summary |
---|
public void | beginFastChildLayout()
mFastChildLayout = true;
|
protected boolean | checkLayoutParams(ViewGroup.LayoutParams lp)
return lp instanceof LayoutParams;
|
private void | clearAllState()Clear all state because the grid will be used for a completely different set of data.
// Clear all layout records and views
mLayoutRecords.clear();
removeAllViews();
// Reset to the top of the grid
resetStateForGridTop();
// Clear recycler because there could be different view types now
mRecycler.clear();
|
public void | computeScroll()
if (mScroller.computeScrollOffset()) {
final int y = mScroller.getCurrY();
final int dy = (int) (y - mLastTouchY);
mLastTouchY = y;
final boolean stopped = !trackMotionScroll(dy, 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 (dy > 0) {
edge = mTopEdge;
} else {
edge = mBottomEdge;
}
edge.onAbsorb(Math.abs((int) mScroller.getCurrVelocity()));
ViewCompat.postInvalidateOnAnimation(this);
}
mScroller.abortAnimation();
}
mTouchMode = TOUCH_MODE_IDLE;
}
}
|
private final boolean | contentFits()
if (mFirstPosition != 0 || getChildCount() != mItemCount) {
return false;
}
int topmost = Integer.MAX_VALUE;
int bottommost = Integer.MIN_VALUE;
for (int i = 0; i < mColCount; i++) {
if (mItemTops[i] < topmost) {
topmost = mItemTops[i];
}
if (mItemBottoms[i] > bottommost) {
bottommost = mItemBottoms[i];
}
}
return topmost >= getPaddingTop() && bottommost <= getHeight() - getPaddingBottom();
|
public void | draw(android.graphics.Canvas canvas)
super.draw(canvas);
if (mTopEdge != null) {
boolean needsInvalidate = false;
if (!mTopEdge.isFinished()) {
mTopEdge.draw(canvas);
needsInvalidate = true;
}
if (!mBottomEdge.isFinished()) {
final int restoreCount = canvas.save();
final int width = getWidth();
canvas.translate(-width, getHeight());
canvas.rotate(180, width, 0);
mBottomEdge.draw(canvas);
canvas.restoreToCount(restoreCount);
needsInvalidate = true;
}
if (needsInvalidate) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
|
private void | dumpItemPositions()
final int childCount = getChildCount();
Log.d(TAG, "dumpItemPositions:");
Log.d(TAG, " => Tops:");
for (int i = 0; i < mColCount; i++) {
Log.d(TAG, " => " + mItemTops[i]);
boolean found = false;
for (int j = 0; j < childCount; j++) {
final View child = getChildAt(j);
if (mItemTops[i] == child.getTop() - mItemMargin) {
found = true;
}
}
if (!found) {
Log.d(TAG, "!!! No top item found for column " + i + " value " + mItemTops[i]);
}
}
Log.d(TAG, " => Bottoms:");
for (int i = 0; i < mColCount; i++) {
Log.d(TAG, " => " + mItemBottoms[i]);
boolean found = false;
for (int j = 0; j < childCount; j++) {
final View child = getChildAt(j);
if (mItemBottoms[i] == child.getBottom()) {
found = true;
}
}
if (!found) {
Log.d(TAG, "!!! No bottom item found for column " + i + " value " + mItemBottoms[i]);
}
}
|
public void | endFastChildLayout()
mFastChildLayout = false;
populate();
|
final int | fillDown(int fromPosition, int overhang)Should be called with mPopulating set to true
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int itemMargin = mItemMargin;
final int colWidth =
(getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount;
final int gridBottom = getHeight() - getPaddingBottom();
final int fillTo = gridBottom + overhang;
int nextCol = getNextColumnDown();
int position = fromPosition;
while (nextCol >= 0 && mItemBottoms[nextCol] < fillTo && position < mItemCount) {
final View child = obtainView(position, null);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (child.getParent() != this) {
if (mInLayout) {
addViewInLayout(child, -1, lp);
} else {
addView(child);
}
}
final int span = Math.min(mColCount, lp.span);
final int widthSize = colWidth * span + itemMargin * (span - 1);
final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
LayoutRecord rec;
if (span > 1) {
rec = getNextRecordDown(position, span);
nextCol = rec.column;
} else {
rec = mLayoutRecords.get(position);
}
boolean invalidateAfter = false;
if (rec == null) {
rec = new LayoutRecord();
mLayoutRecords.put(position, rec);
rec.column = nextCol;
rec.span = span;
} else if (span != rec.span) {
rec.span = span;
rec.column = nextCol;
invalidateAfter = true;
} else {
nextCol = rec.column;
}
if (mHasStableIds) {
final long id = mAdapter.getItemId(position);
rec.id = id;
lp.id = id;
}
lp.column = nextCol;
final int heightSpec;
if (lp.height == LayoutParams.WRAP_CONTENT) {
heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
} else {
heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
}
child.measure(widthSpec, heightSpec);
final int childHeight = child.getMeasuredHeight();
if (invalidateAfter || (childHeight != rec.height && rec.height > 0)) {
invalidateLayoutRecordsAfterPosition(position);
}
rec.height = childHeight;
final int startFrom;
if (span > 1) {
int lowest = mItemBottoms[nextCol];
for (int i = nextCol + 1; i < nextCol + span; i++) {
final int bottom = mItemBottoms[i];
if (bottom > lowest) {
lowest = bottom;
}
}
startFrom = lowest;
} else {
startFrom = mItemBottoms[nextCol];
}
final int childTop = startFrom + itemMargin;
final int childBottom = childTop + childHeight;
final int childLeft = paddingLeft + nextCol * (colWidth + itemMargin);
final int childRight = childLeft + child.getMeasuredWidth();
child.layout(childLeft, childTop, childRight, childBottom);
for (int i = nextCol; i < nextCol + span; i++) {
mItemBottoms[i] = childBottom + rec.getMarginBelow(i - nextCol);
}
nextCol = getNextColumnDown();
position++;
}
int lowestView = 0;
for (int i = 0; i < mColCount; i++) {
if (mItemBottoms[i] > lowestView) {
lowestView = mItemBottoms[i];
}
}
return lowestView - gridBottom;
|
final int | fillUp(int fromPosition, int overhang)Should be called with mPopulating set to true
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int itemMargin = mItemMargin;
final int colWidth =
(getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount;
final int gridTop = getPaddingTop();
final int fillTo = gridTop - overhang;
int nextCol = getNextColumnUp();
int position = fromPosition;
while (nextCol >= 0 && mItemTops[nextCol] > fillTo && position >= 0) {
final View child = obtainView(position, null);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (child.getParent() != this) {
if (mInLayout) {
addViewInLayout(child, 0, lp);
} else {
addView(child, 0);
}
}
final int span = Math.min(mColCount, lp.span);
final int widthSize = colWidth * span + itemMargin * (span - 1);
final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
LayoutRecord rec;
if (span > 1) {
rec = getNextRecordUp(position, span);
nextCol = rec.column;
} else {
rec = mLayoutRecords.get(position);
}
boolean invalidateBefore = false;
if (rec == null) {
rec = new LayoutRecord();
mLayoutRecords.put(position, rec);
rec.column = nextCol;
rec.span = span;
} else if (span != rec.span) {
rec.span = span;
rec.column = nextCol;
invalidateBefore = true;
} else {
nextCol = rec.column;
}
if (mHasStableIds) {
final long id = mAdapter.getItemId(position);
rec.id = id;
lp.id = id;
}
lp.column = nextCol;
final int heightSpec;
if (lp.height == LayoutParams.WRAP_CONTENT) {
heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
} else {
heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
}
child.measure(widthSpec, heightSpec);
final int childHeight = child.getMeasuredHeight();
if (invalidateBefore || (childHeight != rec.height && rec.height > 0)) {
invalidateLayoutRecordsBeforePosition(position);
}
rec.height = childHeight;
final int startFrom;
if (span > 1) {
int highest = mItemTops[nextCol];
for (int i = nextCol + 1; i < nextCol + span; i++) {
final int top = mItemTops[i];
if (top < highest) {
highest = top;
}
}
startFrom = highest;
} else {
startFrom = mItemTops[nextCol];
}
final int childBottom = startFrom;
final int childTop = childBottom - childHeight;
final int childLeft = paddingLeft + nextCol * (colWidth + itemMargin);
final int childRight = childLeft + child.getMeasuredWidth();
child.layout(childLeft, childTop, childRight, childBottom);
for (int i = nextCol; i < nextCol + span; i++) {
mItemTops[i] = childTop - rec.getMarginAbove(i - nextCol) - itemMargin;
}
nextCol = getNextColumnUp();
mFirstPosition = position--;
}
int highestView = getHeight();
for (int i = 0; i < mColCount; i++) {
if (mItemTops[i] < highestView) {
highestView = mItemTops[i];
}
}
return gridTop - highestView;
|
protected com.android.ex.widget.StaggeredGridView$LayoutParams | generateDefaultLayoutParams()
return new LayoutParams(LayoutParams.WRAP_CONTENT);
|
protected com.android.ex.widget.StaggeredGridView$LayoutParams | generateLayoutParams(ViewGroup.LayoutParams lp)
return new LayoutParams(lp);
|
public ViewGroup.LayoutParams | generateLayoutParams(android.util.AttributeSet attrs)
return new LayoutParams(getContext(), attrs);
|
public android.widget.ListAdapter | getAdapter()
return mAdapter;
|
public int | getColumnCount()
return mColCount;
|
public int | getFirstPosition()Return the first adapter position with a view currently attached as
a child view of this grid.
return mFirstPosition;
|
final int | getNextColumnDown()
int result = -1;
int topMost = Integer.MAX_VALUE;
final int colCount = mColCount;
for (int i = 0; i < colCount; i++) {
final int bottom = mItemBottoms[i];
if (bottom < topMost) {
topMost = bottom;
result = i;
}
}
return result;
|
final int | getNextColumnUp()
int result = -1;
int bottomMost = Integer.MIN_VALUE;
final int colCount = mColCount;
for (int i = colCount - 1; i >= 0; i--) {
final int top = mItemTops[i];
if (top > bottomMost) {
bottomMost = top;
result = i;
}
}
return result;
|
final com.android.ex.widget.StaggeredGridView$LayoutRecord | getNextRecordDown(int position, int span)
LayoutRecord rec = mLayoutRecords.get(position);
if (rec == null) {
rec = new LayoutRecord();
rec.span = span;
mLayoutRecords.put(position, rec);
} else if (rec.span != span) {
throw new IllegalStateException("Invalid LayoutRecord! Record had span=" + rec.span +
" but caller requested span=" + span + " for position=" + position);
}
int targetCol = -1;
int topMost = Integer.MAX_VALUE;
final int colCount = mColCount;
for (int i = 0; i <= colCount - span; i++) {
int bottom = Integer.MIN_VALUE;
for (int j = i; j < i + span; j++) {
final int singleBottom = mItemBottoms[j];
if (singleBottom > bottom) {
bottom = singleBottom;
}
}
if (bottom < topMost) {
topMost = bottom;
targetCol = i;
}
}
rec.column = targetCol;
for (int i = 0; i < span; i++) {
rec.setMarginAbove(i, topMost - mItemBottoms[i + targetCol]);
}
return rec;
|
final com.android.ex.widget.StaggeredGridView$LayoutRecord | getNextRecordUp(int position, int span)Return a LayoutRecord for the given position
LayoutRecord rec = mLayoutRecords.get(position);
if (rec == null) {
rec = new LayoutRecord();
rec.span = span;
mLayoutRecords.put(position, rec);
} else if (rec.span != span) {
throw new IllegalStateException("Invalid LayoutRecord! Record had span=" + rec.span +
" but caller requested span=" + span + " for position=" + position);
}
int targetCol = -1;
int bottomMost = Integer.MIN_VALUE;
final int colCount = mColCount;
for (int i = colCount - span; i >= 0; i--) {
int top = Integer.MAX_VALUE;
for (int j = i; j < i + span; j++) {
final int singleTop = mItemTops[j];
if (singleTop < top) {
top = singleTop;
}
}
if (top > bottomMost) {
bottomMost = top;
targetCol = i;
}
}
rec.column = targetCol;
for (int i = 0; i < span; i++) {
rec.setMarginBelow(i, mItemTops[i + targetCol] - bottomMost);
}
return rec;
|
final void | invalidateLayoutRecordsAfterPosition(int position)
int beginAt = mLayoutRecords.size() - 1;
while (beginAt >= 0 && mLayoutRecords.keyAt(beginAt) > position) {
beginAt--;
}
beginAt++;
mLayoutRecords.removeAtRange(beginAt + 1, mLayoutRecords.size() - beginAt);
|
final void | invalidateLayoutRecordsBeforePosition(int position)
int endAt = 0;
while (endAt < mLayoutRecords.size() && mLayoutRecords.keyAt(endAt) < position) {
endAt++;
}
mLayoutRecords.removeAtRange(0, endAt);
|
final void | layoutChildren(boolean queryAdapter)Measure and layout all currently visible children.
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int itemMargin = mItemMargin;
final int colWidth =
(getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount;
int rebuildLayoutRecordsBefore = -1;
int rebuildLayoutRecordsAfter = -1;
Arrays.fill(mItemBottoms, Integer.MIN_VALUE);
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int col = lp.column;
final int position = mFirstPosition + i;
final boolean needsLayout = queryAdapter || child.isLayoutRequested();
if (queryAdapter) {
View newView = obtainView(position, child);
if (newView != child) {
removeViewAt(i);
addView(newView, i);
child = newView;
}
lp = (LayoutParams) child.getLayoutParams(); // Might have changed
}
final int span = Math.min(mColCount, lp.span);
final int widthSize = colWidth * span + itemMargin * (span - 1);
if (needsLayout) {
final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
final int heightSpec;
if (lp.height == LayoutParams.WRAP_CONTENT) {
heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
} else {
heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
}
child.measure(widthSpec, heightSpec);
}
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);
for (int j = col; j < col + span; j++) {
mItemBottoms[j] = childBottom;
}
final LayoutRecord rec = mLayoutRecords.get(position);
if (rec != null && rec.height != childHeight) {
// Invalidate our layout records for everything before this.
rec.height = childHeight;
rebuildLayoutRecordsBefore = position;
}
if (rec != null && rec.span != span) {
// Invalidate our layout records for everything after this.
rec.span = span;
rebuildLayoutRecordsAfter = position;
}
}
// Update mItemBottoms for any empty columns
for (int i = 0; i < mColCount; i++) {
if (mItemBottoms[i] == Integer.MIN_VALUE) {
mItemBottoms[i] = mItemTops[i];
}
}
if (rebuildLayoutRecordsBefore >= 0 || rebuildLayoutRecordsAfter >= 0) {
if (rebuildLayoutRecordsBefore >= 0) {
invalidateLayoutRecordsBeforePosition(rebuildLayoutRecordsBefore);
}
if (rebuildLayoutRecordsAfter >= 0) {
invalidateLayoutRecordsAfterPosition(rebuildLayoutRecordsAfter);
}
for (int i = 0; i < childCount; i++) {
final int position = mFirstPosition + i;
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
LayoutRecord rec = mLayoutRecords.get(position);
if (rec == null) {
rec = new LayoutRecord();
mLayoutRecords.put(position, rec);
}
rec.column = lp.column;
rec.height = child.getHeight();
rec.id = lp.id;
rec.span = Math.min(mColCount, lp.span);
}
}
|
final android.view.View | obtainView(int position, android.view.View optScrap)Obtain a populated view from the adapter. If optScrap is non-null and is not
reused it will be placed in the recycle bin.
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);
}
}
final LayoutParams sglp = (LayoutParams) lp;
sglp.position = position;
sglp.viewType = positionViewType;
return view;
|
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(), child.getTop() + offset,
child.getRight(), child.getBottom() + offset);
}
final int colCount = mColCount;
for (int i = 0; i < colCount; i++) {
mItemTops[i] += offset;
mItemBottoms[i] += offset;
}
|
public boolean | onInterceptTouchEvent(android.view.MotionEvent ev)
mVelocityTracker.addMovement(ev);
final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
mVelocityTracker.clear();
mScroller.abortAnimation();
mLastTouchY = ev.getY();
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
mTouchRemainderY = 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 y = MotionEventCompat.getY(ev, index);
final float dy = y - mLastTouchY + mTouchRemainderY;
final int deltaY = (int) dy;
mTouchRemainderY = dy - deltaY;
if (Math.abs(dy) > mTouchSlop) {
mTouchMode = TOUCH_MODE_DRAGGING;
return true;
}
}
}
return false;
|
protected void | onLayout(boolean changed, int l, int t, int r, int b)
mInLayout = true;
populate();
mInLayout = false;
mForcePopulateOnLayout = false;
final int width = r - l;
final int height = b - t;
mTopEdge.setSize(width, height);
mBottomEdge.setSize(width, height);
|
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);
widthMode = MeasureSpec.EXACTLY;
}
if (heightMode != MeasureSpec.EXACTLY) {
Log.e(TAG, "onMeasure: must have an exact height or match_parent! " +
"Using fallback spec of EXACTLY " + heightSize);
heightMode = MeasureSpec.EXACTLY;
}
setMeasuredDimension(widthSize, heightSize);
if (mColCountSetting == COLUMN_COUNT_AUTO) {
final int colCount = widthSize / mMinColWidth;
if (colCount != mColCount) {
mColCount = colCount;
mForcePopulateOnLayout = true;
}
}
|
public void | onRestoreInstanceState(android.os.Parcelable state)
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
mDataChanged = true;
mFirstPosition = ss.position;
mRestoreOffset = ss.topOffset;
requestLayout();
|
public android.os.Parcelable | onSaveInstanceState()
final Parcelable superState = super.onSaveInstanceState();
final SavedState ss = new SavedState(superState);
final int position = mFirstPosition;
ss.position = position;
if (position >= 0 && mAdapter != null && position < mAdapter.getCount()) {
ss.firstId = mAdapter.getItemId(position);
}
if (getChildCount() > 0) {
ss.topOffset = getChildAt(0).getTop() - mItemMargin - getPaddingTop();
}
return ss;
|
public boolean | onTouchEvent(android.view.MotionEvent ev)
mVelocityTracker.addMovement(ev);
final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
mVelocityTracker.clear();
mScroller.abortAnimation();
mLastTouchY = ev.getY();
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
mTouchRemainderY = 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 y = MotionEventCompat.getY(ev, index);
final float dy = y - mLastTouchY + mTouchRemainderY;
final int deltaY = (int) dy;
mTouchRemainderY = dy - deltaY;
if (Math.abs(dy) > mTouchSlop) {
mTouchMode = TOUCH_MODE_DRAGGING;
}
if (mTouchMode == TOUCH_MODE_DRAGGING) {
mLastTouchY = y;
if (!trackMotionScroll(deltaY, 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.getYVelocity(mVelocityTracker,
mActivePointerId);
if (Math.abs(velocity) > mFlingVelocity) { // TODO
mTouchMode = TOUCH_MODE_FLINGING;
mScroller.fling(0, 0, 0, (int) velocity, 0, 0,
Integer.MIN_VALUE, Integer.MAX_VALUE);
mLastTouchY = 0;
ViewCompat.postInvalidateOnAnimation(this);
} else {
mTouchMode = TOUCH_MODE_IDLE;
}
} break;
}
return true;
|
private void | populate()
if (getWidth() == 0 || getHeight() == 0) {
return;
}
if (mColCount == COLUMN_COUNT_AUTO) {
final int colCount = getWidth() / mMinColWidth;
if (colCount != mColCount) {
mColCount = colCount;
}
}
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);
fillDown(mFirstPosition + getChildCount(), 0);
fillUp(mFirstPosition - 1, 0);
mPopulating = false;
mDataChanged = false;
|
private void | recycleAllViews()
for (int i = 0; i < getChildCount(); i++) {
mRecycler.addScrap(getChildAt(i));
}
if (mInLayout) {
removeAllViewsInLayout();
} else {
removeAllViews();
}
|
private void | recycleOffscreenViews()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.
final int height = getHeight();
final int clearAbove = -mItemMargin;
final int clearBelow = height + mItemMargin;
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 int childCount = getChildCount();
if (childCount > 0) {
// Repair the top and bottom column boundaries from the views we still have
Arrays.fill(mItemTops, Integer.MAX_VALUE);
Arrays.fill(mItemBottoms, Integer.MIN_VALUE);
for (int i = 0; i < childCount; i++){
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int top = child.getTop() - mItemMargin;
final int bottom = child.getBottom();
final LayoutRecord rec = mLayoutRecords.get(mFirstPosition + i);
final int colEnd = lp.column + Math.min(mColCount, lp.span);
for (int col = lp.column; col < colEnd; col++) {
final int colTop = top - rec.getMarginAbove(col - lp.column);
final int colBottom = bottom + rec.getMarginBelow(col - lp.column);
if (colTop < mItemTops[col]) {
mItemTops[col] = colTop;
}
if (colBottom > mItemBottoms[col]) {
mItemBottoms[col] = colBottom;
}
}
}
for (int col = 0; col < mColCount; col++) {
if (mItemTops[col] == Integer.MAX_VALUE) {
// If one was untouched, both were.
mItemTops[col] = 0;
mItemBottoms[col] = 0;
}
}
}
|
public void | requestLayout()
if (!mPopulating && !mFastChildLayout) {
super.requestLayout();
}
|
private void | resetStateForGridTop()Reset all internal state to be at the top of the grid.
// Reset mItemTops and mItemBottoms
final int colCount = mColCount;
if (mItemTops == null || mItemTops.length != colCount) {
mItemTops = new int[colCount];
mItemBottoms = new int[colCount];
}
final int top = getPaddingTop();
Arrays.fill(mItemTops, top);
Arrays.fill(mItemBottoms, top);
// Reset the first visible position in the grid to be item 0
mFirstPosition = 0;
mRestoreOffset = 0;
|
public void | setAdapter(android.widget.ListAdapter 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();
|
public void | setColumnCount(int colCount)Set a fixed number of columns for this grid. Space will be divided evenly
among all columns, respecting the item margin between columns.
The default is 2. (If it were 1, perhaps you should be using a
{@link android.widget.ListView ListView}.)
if (colCount < 1 && colCount != COLUMN_COUNT_AUTO) {
throw new IllegalArgumentException("Column count must be at least 1 - received " +
colCount);
}
final boolean needsPopulate = colCount != mColCount;
mColCount = mColCountSetting = colCount;
if (needsPopulate) {
populate();
}
|
public void | setItemMargin(int marginPixels)Set the margin between items in pixels. This margin is applied
both vertically and horizontally.
final boolean needsPopulate = marginPixels != mItemMargin;
mItemMargin = marginPixels;
if (needsPopulate) {
populate();
}
|
public void | setMinColumnWidth(int minColWidth)Set a minimum column width for
mMinColWidth = minColWidth;
setColumnCount(COLUMN_COUNT_AUTO);
|
public void | setSelectionToTop()Scroll the list so the first visible position in the grid is the first item in the adapter.
// Clear out the views (but don't clear out the layout records or recycler because the data
// has not changed)
removeAllViews();
// Reset to top of grid
resetStateForGridTop();
// Start populating again
populate();
|
private boolean | trackMotionScroll(int deltaY, boolean allowOverScroll)
final boolean contentFits = contentFits();
final int allowOverhang = Math.abs(deltaY);
final int overScrolledBy;
final int movedBy;
if (!contentFits) {
final int overhang;
final boolean up;
mPopulating = true;
if (deltaY > 0) {
overhang = fillUp(mFirstPosition - 1, allowOverhang);
up = true;
} else {
overhang = fillDown(mFirstPosition + getChildCount(), allowOverhang) + mItemMargin;
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 = deltaY > 0 ? mTopEdge : mBottomEdge;
edge.onPull((float) Math.abs(deltaY) / getHeight());
ViewCompat.postInvalidateOnAnimation(this);
}
}
}
return deltaY == 0 || movedBy != 0;
|