Methods Summary |
---|
private boolean | appendOneVisibleItem()
while (true) {
if (mLastVisiblePos != NO_POSITION && mLastVisiblePos < mState.getItemCount() -1 &&
mLastVisiblePos < mGrid.getLastIndex()) {
// append invisible view of saved location till last row
final int index = mLastVisiblePos + 1;
final int row = mGrid.getLocation(index).row;
mGridProvider.createItem(index, row, true);
if (row == mNumRows - 1) {
return false;
}
} else if ((mLastVisiblePos == NO_POSITION && mState.getItemCount() > 0) ||
(mLastVisiblePos != NO_POSITION &&
mLastVisiblePos < mState.getItemCount() - 1)) {
if (mReverseFlowPrimary) {
mGrid.appendItems(mScrollOffsetPrimary);
} else {
mGrid.appendItems(mScrollOffsetPrimary + mSizePrimary);
}
return false;
} else {
return true;
}
}
|
private void | appendVisibleItems()
while (needsAppendVisibleItem()) {
if (appendOneVisibleItem()) {
break;
}
}
|
public boolean | canScrollHorizontally()
// We can scroll horizontally if we have horizontal orientation, or if
// we are vertical and have more than one column.
return mOrientation == HORIZONTAL || mNumRows > 1;
|
public boolean | canScrollVertically()
// We can scroll vertically if we have vertical orientation, or if we
// are horizontal and have more than one row.
return mOrientation == VERTICAL || mNumRows > 1;
|
private void | discardLayoutInfo()
mGrid = null;
mRows = null;
mRowSizeSecondary = null;
mFirstVisiblePos = -1;
mLastVisiblePos = -1;
mRowSecondarySizeRefresh = false;
|
private void | dispatchChildSelected()
if (mChildSelectedListener == null) {
return;
}
View view = mFocusPosition == NO_POSITION ? null : findViewByPosition(mFocusPosition);
if (view != null) {
RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(view);
mChildSelectedListener.onChildSelected(mBaseGridView, view, mFocusPosition,
vh == null? NO_ID: vh.getItemId());
} else {
mChildSelectedListener.onChildSelected(mBaseGridView, null, NO_POSITION, NO_ID);
}
// Children may request layout when a child selection event occurs (such as a change of
// padding on the current and previously selected rows).
// If in layout, a child requesting layout may have been laid out before the selection
// callback.
// If it was not, the child will be laid out after the selection callback.
// If so, the layout request will be honoured though the view system will emit a double-
// layout warning.
// If not in layout, we may be scrolling in which case the child layout request will be
// eaten by recyclerview. Post a requestLayout.
if (!mInLayout && !mBaseGridView.isLayoutRequested()) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
if (getChildAt(i).isLayoutRequested()) {
forceRequestLayout();
break;
}
}
}
|
protected void | fastRelayout(boolean scrollToFocus)
updateScrollController();
List<Integer>[] rows = mGrid.getItemPositionsInRows(mFirstVisiblePos, mLastVisiblePos);
// relayout and repositioning views on each row
for (int i = 0; i < mNumRows; i++) {
List<Integer> row = rows[i];
final int startSecondary = getRowStartSecondary(i) - mScrollOffsetSecondary;
for (int j = 0, size = row.size(); j < size; j++) {
final int position = row.get(j);
View view = findViewByPosition(position);
int primaryDelta, end;
int start = getViewMin(view);
int oldPrimarySize = (mOrientation == HORIZONTAL) ?
view.getMeasuredWidth() :
view.getMeasuredHeight();
LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (lp.viewNeedsUpdate()) {
int index = mBaseGridView.indexOfChild(view);
detachAndScrapView(view, mRecycler);
view = getViewForPosition(position);
addView(view, index);
}
if (view.isLayoutRequested()) {
measureChild(view);
}
if (mOrientation == HORIZONTAL) {
end = start + view.getMeasuredWidth();
primaryDelta = view.getMeasuredWidth() - oldPrimarySize;
if (primaryDelta != 0) {
for (int k = j + 1; k < size; k++) {
findViewByPosition(row.get(k)).offsetLeftAndRight(primaryDelta);
}
}
} else {
end = start + view.getMeasuredHeight();
primaryDelta = view.getMeasuredHeight() - oldPrimarySize;
if (primaryDelta != 0) {
for (int k = j + 1; k < size; k++) {
findViewByPosition(row.get(k)).offsetTopAndBottom(primaryDelta);
}
}
}
layoutChild(i, view, start, end, startSecondary);
}
}
updateRowsMinMax();
appendVisibleItems();
prependVisibleItems();
updateRowsMinMax();
updateScrollMin();
updateScrollMax();
updateScrollSecondAxis();
if (scrollToFocus) {
View focusView = findViewByPosition(mFocusPosition == NO_POSITION ? 0 : mFocusPosition);
scrollToView(focusView, false);
}
|
private int | findImmediateChildIndex(android.view.View view)
while (view != null && view != mBaseGridView) {
int index = mBaseGridView.indexOfChild(view);
if (index >= 0) {
return index;
}
view = (View) view.getParent();
}
return NO_POSITION;
|
private void | forceRequestLayout()
if (DEBUG) Log.v(getTag(), "forceRequestLayout");
// RecyclerView prevents us from requesting layout in many cases
// (during layout, during scroll, etc.)
// For secondary row size wrap_content support we currently need a
// second layout pass to update the measured size after having measured
// and added child views in layoutChildren.
// Force the second layout by posting a delayed runnable.
// TODO: investigate allowing a second layout pass,
// or move child add/measure logic to the measure phase.
ViewCompat.postOnAnimation(mBaseGridView, mRequestLayoutRunnable);
|
public RecyclerView.LayoutParams | generateDefaultLayoutParams()
return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
|
public RecyclerView.LayoutParams | generateLayoutParams(android.content.Context context, android.util.AttributeSet attrs)
return new LayoutParams(context, attrs);
|
public RecyclerView.LayoutParams | generateLayoutParams(ViewGroup.LayoutParams lp)
if (lp instanceof LayoutParams) {
return new LayoutParams((LayoutParams) lp);
} else if (lp instanceof RecyclerView.LayoutParams) {
return new LayoutParams((RecyclerView.LayoutParams) lp);
} else if (lp instanceof MarginLayoutParams) {
return new LayoutParams((MarginLayoutParams) lp);
} else {
return new LayoutParams(lp);
}
|
private boolean | getAlignedPosition(android.view.View view, int[] deltas)
int scrollPrimary = getPrimarySystemScrollPosition(view);
int scrollSecondary = getSecondarySystemScrollPosition(view);
if (DEBUG) {
Log.v(getTag(), "getAlignedPosition " + scrollPrimary + " " + scrollSecondary
+ " " + mWindowAlignment);
Log.v(getTag(), "getAlignedPosition " + mScrollOffsetPrimary + " " + mScrollOffsetSecondary);
}
scrollPrimary -= mScrollOffsetPrimary;
scrollSecondary -= mScrollOffsetSecondary;
if (scrollPrimary != 0 || scrollSecondary != 0) {
deltas[0] = scrollPrimary;
deltas[1] = scrollSecondary;
return true;
}
return false;
|
int | getChildDrawingOrder(android.support.v7.widget.RecyclerView recyclerView, int childCount, int i)
View view = findViewByPosition(mFocusPosition);
if (view == null) {
return i;
}
int focusIndex = recyclerView.indexOfChild(view);
// supposely 0 1 2 3 4 5 6 7 8 9, 4 is the center item
// drawing order is 0 1 2 3 9 8 7 6 5 4
if (i < focusIndex) {
return i;
} else if (i < childCount - 1) {
return focusIndex + childCount - 1 - i;
} else {
return focusIndex;
}
|
public int | getFocusScrollStrategy()
return mFocusScrollStrategy;
|
public int | getHorizontalMargin()
return mHorizontalMargin;
|
public int | getItemAlignmentOffset()
return mItemAlignment.mainAxis().getItemAlignmentOffset();
|
public float | getItemAlignmentOffsetPercent()
return mItemAlignment.mainAxis().getItemAlignmentOffsetPercent();
|
public int | getItemAlignmentViewId()
return mItemAlignment.mainAxis().getItemAlignmentViewId();
|
private int | getMovement(int direction)
int movement = View.FOCUS_LEFT;
if (mOrientation == HORIZONTAL) {
switch(direction) {
case View.FOCUS_LEFT:
movement = (!mReverseFlowPrimary) ? PREV_ITEM : NEXT_ITEM;
break;
case View.FOCUS_RIGHT:
movement = (!mReverseFlowPrimary) ? NEXT_ITEM : PREV_ITEM;
break;
case View.FOCUS_UP:
movement = PREV_ROW;
break;
case View.FOCUS_DOWN:
movement = NEXT_ROW;
break;
}
} else if (mOrientation == VERTICAL) {
switch(direction) {
case View.FOCUS_LEFT:
movement = (!mReverseFlowPrimary) ? PREV_ROW : NEXT_ROW;
break;
case View.FOCUS_RIGHT:
movement = (!mReverseFlowPrimary) ? NEXT_ROW : PREV_ROW;
break;
case View.FOCUS_UP:
movement = PREV_ITEM;
break;
case View.FOCUS_DOWN:
movement = NEXT_ITEM;
break;
}
}
return movement;
|
private boolean | getNoneAlignedPosition(android.view.View view, int[] deltas)
int pos = getPositionByView(view);
int viewMin = getViewMin(view);
int viewMax = getViewMax(view);
// we either align "firstView" to left/top padding edge
// or align "lastView" to right/bottom padding edge
View firstView = null;
View lastView = null;
int paddingLow = mWindowAlignment.mainAxis().getPaddingLow();
int clientSize = mWindowAlignment.mainAxis().getClientSize();
final int row = mGrid.getLocation(pos).row;
if (viewMin < paddingLow) {
// view enters low padding area:
firstView = view;
if (mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_PAGE) {
// scroll one "page" left/top,
// align first visible item of the "page" at the low padding edge.
while (!prependOneVisibleItem()) {
List<Integer> positions =
mGrid.getItemPositionsInRows(mFirstVisiblePos, pos)[row];
firstView = findViewByPosition(positions.get(0));
if (viewMax - getViewMin(firstView) > clientSize) {
if (positions.size() > 1) {
firstView = findViewByPosition(positions.get(1));
}
break;
}
}
}
} else if (viewMax > clientSize + paddingLow) {
// view enters high padding area:
if (mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_PAGE) {
// scroll whole one page right/bottom, align view at the low padding edge.
firstView = view;
do {
List<Integer> positions =
mGrid.getItemPositionsInRows(pos, mLastVisiblePos)[row];
lastView = findViewByPosition(positions.get(positions.size() - 1));
if (getViewMax(lastView) - viewMin > clientSize) {
lastView = null;
break;
}
} while (!appendOneVisibleItem());
if (lastView != null) {
// however if we reached end, we should align last view.
firstView = null;
}
} else {
lastView = view;
}
}
int scrollPrimary = 0;
int scrollSecondary = 0;
if (firstView != null) {
scrollPrimary = getViewMin(firstView) - paddingLow;
} else if (lastView != null) {
scrollPrimary = getViewMax(lastView) - (paddingLow + clientSize);
}
View secondaryAlignedView;
if (firstView != null) {
secondaryAlignedView = firstView;
} else if (lastView != null) {
secondaryAlignedView = lastView;
} else {
secondaryAlignedView = view;
}
scrollSecondary = getSecondarySystemScrollPosition(secondaryAlignedView);
scrollSecondary -= mScrollOffsetSecondary;
if (scrollPrimary != 0 || scrollSecondary != 0) {
deltas[0] = scrollPrimary;
deltas[1] = scrollSecondary;
return true;
}
return false;
|
final int | getOpticalBottom(android.view.View v)
return ((LayoutParams) v.getLayoutParams()).getOpticalBottom(v);
|
final int | getOpticalLeft(android.view.View v)
return ((LayoutParams) v.getLayoutParams()).getOpticalLeft(v);
|
final int | getOpticalRight(android.view.View v)
return ((LayoutParams) v.getLayoutParams()).getOpticalRight(v);
|
final int | getOpticalTop(android.view.View v)
return ((LayoutParams) v.getLayoutParams()).getOpticalTop(v);
|
private int | getPositionByIndex(int index)
return getPositionByView(getChildAt(index));
|
private int | getPositionByView(android.view.View view)
if (view == null) {
return NO_POSITION;
}
LayoutParams params = (LayoutParams) view.getLayoutParams();
if (params == null || params.isItemRemoved()) {
// when item is removed, the position value can be any value.
return NO_POSITION;
}
return params.getViewPosition();
|
private int | getPrimarySystemScrollPosition(android.view.View view)
final int viewCenterPrimary = mScrollOffsetPrimary + getViewCenter(view);
final int viewMin = getViewMin(view);
final int viewMax = getViewMax(view);
// TODO: change to use State object in onRequestChildFocus()
boolean isMin, isMax;
if (!mReverseFlowPrimary) {
isMin = mFirstVisiblePos == 0;
isMax = mLastVisiblePos == (mState == null ?
getItemCount() : mState.getItemCount()) - 1;
} else {
isMax = mFirstVisiblePos == 0;
isMin = mLastVisiblePos == (mState == null ?
getItemCount() : mState.getItemCount()) - 1;
}
for (int i = getChildCount() - 1; (isMin || isMax) && i >= 0; i--) {
View v = getChildAt(i);
if (v == view || v == null) {
continue;
}
if (isMin && getViewMin(v) < viewMin) {
isMin = false;
}
if (isMax && getViewMax(v) > viewMax) {
isMax = false;
}
}
return mWindowAlignment.mainAxis().getSystemScrollPos(viewCenterPrimary, isMin, isMax);
|
public boolean | getPruneChild()
return mPruneChild;
|
private int | getRowSizeSecondary(int rowIndex)
if (mFixedRowSizeSecondary != 0) {
return mFixedRowSizeSecondary;
}
if (mRowSizeSecondary == null) {
return 0;
}
return mRowSizeSecondary[rowIndex];
|
private int | getRowStartSecondary(int rowIndex)
int start = 0;
// Iterate from left to right, which is a different index traversal
// in RTL flow
if (mReverseFlowSecondary) {
for (int i = mNumRows-1; i > rowIndex; i--) {
start += getRowSizeSecondary(i) + mMarginSecondary;
}
} else {
for (int i = 0; i < rowIndex; i++) {
start += getRowSizeSecondary(i) + mMarginSecondary;
}
}
return start;
|
int | getScrollOffsetX()
return mOrientation == HORIZONTAL ? mScrollOffsetPrimary : mScrollOffsetSecondary;
|
int | getScrollOffsetY()
return mOrientation == HORIZONTAL ? mScrollOffsetSecondary : mScrollOffsetPrimary;
|
private boolean | getScrollPosition(android.view.View view, int[] deltas)
switch (mFocusScrollStrategy) {
case BaseGridView.FOCUS_SCROLL_ALIGNED:
default:
return getAlignedPosition(view, deltas);
case BaseGridView.FOCUS_SCROLL_ITEM:
case BaseGridView.FOCUS_SCROLL_PAGE:
return getNoneAlignedPosition(view, deltas);
}
|
private int | getSecondarySystemScrollPosition(android.view.View view)
int viewCenterSecondary = mScrollOffsetSecondary + getViewCenterSecondary(view);
int pos = getPositionByView(view);
StaggeredGrid.Location location = mGrid.getLocation(pos);
final int row = location.row;
final boolean isMin, isMax;
if (!mReverseFlowSecondary) {
isMin = row == 0;
isMax = row == mGrid.getNumRows() - 1;
} else {
isMax = row == 0;
isMin = row == mGrid.getNumRows() - 1;
}
return mWindowAlignment.secondAxis().getSystemScrollPos(viewCenterSecondary, isMin, isMax);
|
public int | getSelection()
return mFocusPosition;
|
private int | getSizeSecondary()
int rightmostIndex = mReverseFlowSecondary ? 0 : mNumRows - 1;
return getRowStartSecondary(rightmostIndex) + getRowSizeSecondary(rightmostIndex);
|
private java.lang.String | getTag()
return TAG + ":" + mBaseGridView.getId();
|
public int | getVerticalMargin()
return mVerticalMargin;
|
private int | getViewCenter(android.view.View view)
return (mOrientation == HORIZONTAL) ? getViewCenterX(view) : getViewCenterY(view);
|
private int | getViewCenterSecondary(android.view.View view)
return (mOrientation == HORIZONTAL) ? getViewCenterY(view) : getViewCenterX(view);
|
private int | getViewCenterX(android.view.View v)
LayoutParams p = (LayoutParams) v.getLayoutParams();
return p.getOpticalLeft(v) + p.getAlignX();
|
private int | getViewCenterY(android.view.View v)
LayoutParams p = (LayoutParams) v.getLayoutParams();
return p.getOpticalTop(v) + p.getAlignY();
|
protected android.view.View | getViewForPosition(int position)
return mRecycler.getViewForPosition(position);
|
private int | getViewMax(android.view.View v)
return (mOrientation == HORIZONTAL) ? getOpticalRight(v) : getOpticalBottom(v);
|
private int | getViewMin(android.view.View v)
return (mOrientation == HORIZONTAL) ? getOpticalLeft(v) : getOpticalTop(v);
|
public void | getViewSelectedOffsets(android.view.View view, int[] offsets)
if (mOrientation == HORIZONTAL) {
offsets[0] = getPrimarySystemScrollPosition(view) - mScrollOffsetPrimary;
offsets[1] = getSecondarySystemScrollPosition(view) - mScrollOffsetSecondary;
} else {
offsets[1] = getPrimarySystemScrollPosition(view) - mScrollOffsetPrimary;
offsets[0] = getSecondarySystemScrollPosition(view) - mScrollOffsetSecondary;
}
|
public int | getWindowAlignment()
return mWindowAlignment.mainAxis().getWindowAlignment();
|
public int | getWindowAlignmentOffset()
return mWindowAlignment.mainAxis().getWindowAlignmentOffset();
|
public float | getWindowAlignmentOffsetPercent()
return mWindowAlignment.mainAxis().getWindowAlignmentOffsetPercent();
|
boolean | gridOnRequestFocusInDescendants(android.support.v7.widget.RecyclerView recyclerView, int direction, android.graphics.Rect previouslyFocusedRect)
switch (mFocusScrollStrategy) {
case BaseGridView.FOCUS_SCROLL_ALIGNED:
default:
return gridOnRequestFocusInDescendantsAligned(recyclerView,
direction, previouslyFocusedRect);
case BaseGridView.FOCUS_SCROLL_PAGE:
case BaseGridView.FOCUS_SCROLL_ITEM:
return gridOnRequestFocusInDescendantsUnaligned(recyclerView,
direction, previouslyFocusedRect);
}
|
private boolean | gridOnRequestFocusInDescendantsAligned(android.support.v7.widget.RecyclerView recyclerView, int direction, android.graphics.Rect previouslyFocusedRect)
View view = findViewByPosition(mFocusPosition);
if (view != null) {
boolean result = view.requestFocus(direction, previouslyFocusedRect);
if (!result && DEBUG) {
Log.w(getTag(), "failed to request focus on " + view);
}
return result;
}
return false;
|
private boolean | gridOnRequestFocusInDescendantsUnaligned(android.support.v7.widget.RecyclerView recyclerView, int direction, android.graphics.Rect previouslyFocusedRect)
// focus to view not overlapping padding area to avoid scrolling in gaining focus
int index;
int increment;
int end;
int count = getChildCount();
if ((direction & View.FOCUS_FORWARD) != 0) {
index = 0;
increment = 1;
end = count;
} else {
index = count - 1;
increment = -1;
end = -1;
}
int left = mWindowAlignment.mainAxis().getPaddingLow();
int right = mWindowAlignment.mainAxis().getClientSize() + left;
for (int i = index; i != end; i += increment) {
View child = getChildAt(i);
if (child.getVisibility() == View.VISIBLE) {
if (getViewMin(child) >= left && getViewMax(child) <= right) {
if (child.requestFocus(direction, previouslyFocusedRect)) {
return true;
}
}
}
}
return false;
|
protected boolean | hasDoneFirstLayout()
return mGrid != null;
|
boolean | hasPreviousViewInSameRow(int pos)
if (mGrid == null || pos == NO_POSITION) {
return false;
}
if (mFirstVisiblePos > 0) {
return true;
}
final int focusedRow = mGrid.getLocation(pos).row;
for (int i = getChildCount() - 1; i >= 0; i--) {
int position = getPositionByIndex(i);
StaggeredGrid.Location loc = mGrid.getLocation(position);
if (loc != null && loc.row == focusedRow) {
if (position < pos) {
return true;
}
}
}
return false;
|
private int | init(int focusPosition)Re-initialize data structures for a data change or handling invisible
selection. The method tries its best to preserve position information so
that staggered grid looks same before and after re-initialize.
final int newItemCount = mState.getItemCount();
// Force the re-init path in the following conditional
if (newItemCount == 0) {
focusPosition = NO_POSITION;
} else if (focusPosition == NO_POSITION && newItemCount > 0) {
// if focus position is never set before, initialize it to 0
focusPosition = 0;
}
// If adapter has changed then caches are invalid; otherwise,
// we try to maintain each row's position if number of rows keeps the same
// and existing mGrid contains the focusPosition.
if (mRows != null && mNumRows == mRows.length &&
mGrid != null && mGrid.getSize() > 0 && focusPosition >= 0 &&
focusPosition >= mGrid.getFirstIndex() &&
focusPosition <= mGrid.getLastIndex()) {
// strip mGrid to a subset (like a column) that contains focusPosition
mGrid.stripDownTo(focusPosition);
// make sure that remaining items do not exceed new adapter size
int firstIndex = mGrid.getFirstIndex();
int lastIndex = mGrid.getLastIndex();
if (DEBUG) {
Log .v(getTag(), "mGrid firstIndex " + firstIndex + " lastIndex " + lastIndex);
}
for (int i = lastIndex; i >=firstIndex; i--) {
if (i >= newItemCount) {
mGrid.removeLast();
}
}
if (mGrid.getSize() == 0) {
focusPosition = newItemCount - 1;
// initialize row start locations
for (int i = 0; i < mNumRows; i++) {
mRows[i].low = 0;
mRows[i].high = 0;
}
if (DEBUG) Log.v(getTag(), "mGrid zero size");
} else {
// initialize row start locations
for (int i = 0; i < mNumRows; i++) {
mRows[i].low = Integer.MAX_VALUE;
mRows[i].high = Integer.MIN_VALUE;
}
firstIndex = mGrid.getFirstIndex();
lastIndex = mGrid.getLastIndex();
if (focusPosition > lastIndex) {
focusPosition = mGrid.getLastIndex();
}
if (DEBUG) {
Log.v(getTag(), "mGrid firstIndex " + firstIndex + " lastIndex "
+ lastIndex + " focusPosition " + focusPosition);
}
// fill rows with minimal view positions of the subset
for (int i = firstIndex; i <= lastIndex; i++) {
View v = findViewByPosition(i);
if (v == null) {
continue;
}
int row = mGrid.getLocation(i).row;
int low = getViewMin(v) + mScrollOffsetPrimary;
if (low < mRows[row].low) {
mRows[row].low = mRows[row].high = low;
}
}
int firstItemRowPosition = mRows[mGrid.getLocation(firstIndex).row].low;
if (firstItemRowPosition == Integer.MAX_VALUE) {
firstItemRowPosition = 0;
}
if (mState.didStructureChange()) {
// if there is structure change, the removed item might be in the
// subset, so it is meaningless to maintain the low locations.
for (int i = 0; i < mNumRows; i++) {
mRows[i].low = firstItemRowPosition;
mRows[i].high = firstItemRowPosition;
}
} else {
// fill other rows that does not include the subset using first item
for (int i = 0; i < mNumRows; i++) {
if (mRows[i].low == Integer.MAX_VALUE) {
mRows[i].low = mRows[i].high = firstItemRowPosition;
}
}
}
}
// Same adapter, we can reuse any attached views
detachAndScrapAttachedViews(mRecycler);
updateScrollController();
} else {
// otherwise recreate data structure
mRows = new StaggeredGrid.Row[mNumRows];
for (int i = 0; i < mNumRows; i++) {
mRows[i] = new StaggeredGrid.Row();
}
mGrid = new StaggeredGridDefault();
mGrid.setReversedFlow(mOrientation == HORIZONTAL && mReverseFlowPrimary);
if (newItemCount == 0) {
focusPosition = NO_POSITION;
} else if (focusPosition >= newItemCount) {
focusPosition = newItemCount - 1;
}
// Adapter may have changed so remove all attached views permanently
removeAndRecycleAllViews(mRecycler);
initScrollController();
}
mGrid.setProvider(mGridProvider);
// mGrid share the same Row array information
mGrid.setRows(mRows);
mFirstVisiblePos = mLastVisiblePos = NO_POSITION;
updateScrollSecondAxis();
return focusPosition;
|
private void | initScrollController()
mWindowAlignment.reset();
mWindowAlignment.horizontal.setSize(getWidth());
mWindowAlignment.vertical.setSize(getHeight());
mWindowAlignment.horizontal.setPadding(getPaddingLeft(), getPaddingRight());
mWindowAlignment.vertical.setPadding(getPaddingTop(), getPaddingBottom());
mSizePrimary = mWindowAlignment.mainAxis().getSize();
mScrollOffsetPrimary = -mWindowAlignment.mainAxis().getPaddingLow();
mScrollOffsetSecondary = -mWindowAlignment.secondAxis().getPaddingLow();
if (DEBUG) {
Log.v(getTag(), "initScrollController mSizePrimary " + mSizePrimary
+ " mWindowAlignment " + mWindowAlignment
+ " mScrollOffsetPrimary " + mScrollOffsetPrimary);
}
|
boolean | isFocusSearchDisabled()
return mFocusSearchDisabled;
|
public boolean | isItemAlignmentOffsetWithPadding()
return mItemAlignment.mainAxis().isItemAlignmentOffsetWithPadding();
|
public boolean | isScrollEnabled()
return mScrollEnabled;
|
private void | layoutChild(int rowIndex, android.view.View v, int start, int end, int startSecondary)
int sizeSecondary = mOrientation == HORIZONTAL ? v.getMeasuredHeight()
: v.getMeasuredWidth();
if (mFixedRowSizeSecondary > 0) {
sizeSecondary = Math.min(sizeSecondary, mFixedRowSizeSecondary);
}
final int verticalGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
final int horizontalGravity = (mReverseFlowPrimary || mReverseFlowSecondary) ?
Gravity.getAbsoluteGravity(mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK, View.LAYOUT_DIRECTION_RTL) :
mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
if (mOrientation == HORIZONTAL && verticalGravity == Gravity.TOP
|| mOrientation == VERTICAL && horizontalGravity == Gravity.LEFT) {
// do nothing
} else if (mOrientation == HORIZONTAL && verticalGravity == Gravity.BOTTOM
|| mOrientation == VERTICAL && horizontalGravity == Gravity.RIGHT) {
startSecondary += getRowSizeSecondary(rowIndex) - sizeSecondary;
} else if (mOrientation == HORIZONTAL && verticalGravity == Gravity.CENTER_VERTICAL
|| mOrientation == VERTICAL && horizontalGravity == Gravity.CENTER_HORIZONTAL) {
startSecondary += (getRowSizeSecondary(rowIndex) - sizeSecondary) / 2;
}
int left, top, right, bottom;
if (mOrientation == HORIZONTAL) {
left = start;
top = startSecondary;
right = end;
bottom = startSecondary + sizeSecondary;
} else {
top = start;
left = startSecondary;
bottom = end;
right = startSecondary + sizeSecondary;
}
v.layout(left, top, right, bottom);
updateChildOpticalInsets(v, left, top, right, bottom);
updateChildAlignments(v);
|
private void | leaveContext()Discard saved Recycler and State.
mRecycler = null;
mState = null;
|
private void | measureChild(android.view.View child)
final ViewGroup.LayoutParams lp = child.getLayoutParams();
final int secondarySpec = (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT) ?
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) :
MeasureSpec.makeMeasureSpec(mFixedRowSizeSecondary, MeasureSpec.EXACTLY);
int widthSpec, heightSpec;
if (mOrientation == HORIZONTAL) {
widthSpec = ViewGroup.getChildMeasureSpec(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
0, lp.width);
heightSpec = ViewGroup.getChildMeasureSpec(secondarySpec, 0, lp.height);
} else {
heightSpec = ViewGroup.getChildMeasureSpec(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
0, lp.height);
widthSpec = ViewGroup.getChildMeasureSpec(secondarySpec, 0, lp.width);
}
child.measure(widthSpec, heightSpec);
if (DEBUG) Log.v(getTag(), "measureChild secondarySpec " + Integer.toHexString(secondarySpec) +
" widthSpec " + Integer.toHexString(widthSpec) +
" heightSpec " + Integer.toHexString(heightSpec) +
" measuredWidth " + child.getMeasuredWidth() +
" measuredHeight " + child.getMeasuredHeight());
if (DEBUG) Log.v(getTag(), "child lp width " + lp.width + " height " + lp.height);
|
private void | measureScrapChild(int position, int widthSpec, int heightSpec, int[] measuredDimension)
View view = mRecycler.getViewForPosition(position);
if (view != null) {
LayoutParams p = (LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
getPaddingLeft() + getPaddingRight(), p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
getPaddingTop() + getPaddingBottom(), p.height);
view.measure(childWidthSpec, childHeightSpec);
measuredDimension[0] = view.getMeasuredWidth();
measuredDimension[1] = view.getMeasuredHeight();
mRecycler.recycleView(view);
}
|
private boolean | needsAppendVisibleItem()
if (mReverseFlowPrimary) {
for (int i = 0; i < mNumRows; i++) {
if (mRows[i].low == mRows[i].high) {
if (mRows[i].low > mScrollOffsetPrimary) {
return true;
}
} else if (mRows[i].low - mMarginPrimary > mScrollOffsetPrimary) {
return true;
}
}
} else {
int right = mScrollOffsetPrimary + mSizePrimary;
for (int i = 0; i < mNumRows; i++) {
if (mRows[i].low == mRows[i].high) {
if (mRows[i].high < right) {
return true;
}
} else if (mRows[i].high < right - mMarginPrimary) {
return true;
}
}
}
return false;
|
private boolean | needsPrependVisibleItem()
if (mReverseFlowPrimary) {
int right = mScrollOffsetPrimary + mSizePrimary;
for (int i = 0; i < mNumRows; i++) {
if (mRows[i].low == mRows[i].high) {
if (mRows[i].high < right) {
return true;
}
} else if (mRows[i].high < right - mMarginPrimary) {
return true;
}
}
} else {
for (int i = 0; i < mNumRows; i++) {
if (mRows[i].low == mRows[i].high) {
if (mRows[i].low > mScrollOffsetPrimary) {
return true;
}
} else if (mRows[i].low - mMarginPrimary > mScrollOffsetPrimary) {
return true;
}
}
}
return false;
|
private void | offsetChildrenPrimary(int increment)
final int childCount = getChildCount();
if (mOrientation == VERTICAL) {
for (int i = 0; i < childCount; i++) {
getChildAt(i).offsetTopAndBottom(increment);
}
} else {
for (int i = 0; i < childCount; i++) {
getChildAt(i).offsetLeftAndRight(increment);
}
}
|
private void | offsetChildrenSecondary(int increment)
final int childCount = getChildCount();
if (mOrientation == HORIZONTAL) {
for (int i = 0; i < childCount; i++) {
getChildAt(i).offsetTopAndBottom(increment);
}
} else {
for (int i = 0; i < childCount; i++) {
getChildAt(i).offsetLeftAndRight(increment);
}
}
|
public void | onAdapterChanged(RecyclerView.Adapter oldAdapter, RecyclerView.Adapter newAdapter)
if (DEBUG) Log.v(getTag(), "onAdapterChanged to " + newAdapter);
if (oldAdapter != null) {
discardLayoutInfo();
mFocusPosition = NO_POSITION;
mFocusPositionOffset = 0;
mChildrenStates.clear();
}
super.onAdapterChanged(oldAdapter, newAdapter);
|
public boolean | onAddFocusables(android.support.v7.widget.RecyclerView recyclerView, java.util.ArrayList views, int direction, int focusableMode)
if (mFocusSearchDisabled) {
return true;
}
// If this viewgroup or one of its children currently has focus then we
// consider our children for focus searching in main direction on the same row.
// If this viewgroup has no focus and using focus align, we want the system
// to ignore our children and pass focus to the viewgroup, which will pass
// focus on to its children appropriately.
// If this viewgroup has no focus and not using focus align, we want to
// consider the child that does not overlap with padding area.
if (recyclerView.hasFocus()) {
final int movement = getMovement(direction);
if (movement != PREV_ITEM && movement != NEXT_ITEM) {
// Move on secondary direction uses default addFocusables().
return false;
}
final View focused = recyclerView.findFocus();
final int focusedPos = getPositionByIndex(findImmediateChildIndex(focused));
// Add focusables of focused item.
if (focusedPos != NO_POSITION) {
findViewByPosition(focusedPos).addFocusables(views, direction, focusableMode);
}
final int focusedRow = mGrid != null && focusedPos != NO_POSITION ?
mGrid.getLocation(focusedPos).row : NO_POSITION;
// Add focusables of next neighbor of same row on the focus search direction.
if (mGrid != null) {
final int focusableCount = views.size();
for (int i = 0, count = getChildCount(); i < count; i++) {
int index = movement == NEXT_ITEM ? i : count - 1 - i;
final View child = getChildAt(index);
if (child.getVisibility() != View.VISIBLE) {
continue;
}
int position = getPositionByIndex(index);
StaggeredGrid.Location loc = mGrid.getLocation(position);
if (focusedRow == NO_POSITION || (loc != null && loc.row == focusedRow)) {
if (focusedPos == NO_POSITION ||
(movement == NEXT_ITEM && position > focusedPos)
|| (movement == PREV_ITEM && position < focusedPos)) {
child.addFocusables(views, direction, focusableMode);
if (views.size() > focusableCount) {
break;
}
}
}
}
}
} else {
if (mFocusScrollStrategy != BaseGridView.FOCUS_SCROLL_ALIGNED) {
// adding views not overlapping padding area to avoid scrolling in gaining focus
int left = mWindowAlignment.mainAxis().getPaddingLow();
int right = mWindowAlignment.mainAxis().getClientSize() + left;
int focusableCount = views.size();
for (int i = 0, count = getChildCount(); i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() == View.VISIBLE) {
if (getViewMin(child) >= left && getViewMax(child) <= right) {
child.addFocusables(views, direction, focusableMode);
}
}
}
// if we cannot find any, then just add all children.
if (views.size() == focusableCount) {
for (int i = 0, count = getChildCount(); i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() == View.VISIBLE) {
child.addFocusables(views, direction, focusableMode);
}
}
if (views.size() != focusableCount) {
return true;
}
} else {
return true;
}
// if still cannot find any, fall through and add itself
}
if (recyclerView.isFocusable()) {
views.add(recyclerView);
}
}
return true;
|
public android.view.View | onFocusSearchFailed(android.view.View focused, int direction, android.support.v7.widget.RecyclerView.Recycler recycler, android.support.v7.widget.RecyclerView.State state)
if (DEBUG) Log.v(getTag(), "onFocusSearchFailed direction " + direction);
View view = null;
int movement = getMovement(direction);
final boolean isScroll = mBaseGridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE;
if (mNumRows == 1) {
// for simple row, use LinearSmoothScroller to smooth animation.
// It will stay at a fixed cap speed in continuous scroll.
if (movement == NEXT_ITEM) {
int newPos = mFocusPosition + mNumRows;
if (newPos < getItemCount() && mScrollEnabled) {
setSelectionSmooth(mBaseGridView, newPos);
view = focused;
} else {
if (isScroll || !mFocusOutEnd) {
view = focused;
}
}
} else if (movement == PREV_ITEM){
int newPos = mFocusPosition - mNumRows;
if (newPos >= 0 && mScrollEnabled) {
setSelectionSmooth(mBaseGridView, newPos);
view = focused;
} else {
if (isScroll || !mFocusOutFront) {
view = focused;
}
}
}
} else if (mNumRows > 1) {
// for possible staggered grid, we need guarantee focus to same row/column.
// TODO: we may also use LinearSmoothScroller.
saveContext(recycler, state);
final FocusFinder ff = FocusFinder.getInstance();
if (movement == NEXT_ITEM) {
while (view == null && !appendOneVisibleItem()) {
view = ff.findNextFocus(mBaseGridView, focused, direction);
}
} else if (movement == PREV_ITEM){
while (view == null && !prependOneVisibleItem()) {
view = ff.findNextFocus(mBaseGridView, focused, direction);
}
}
if (view == null) {
// returning the same view to prevent focus lost when scrolling past the end of the list
if (movement == PREV_ITEM) {
view = mFocusOutFront && !isScroll ? null : focused;
} else if (movement == NEXT_ITEM){
view = mFocusOutEnd && !isScroll ? null : focused;
}
}
leaveContext();
}
if (DEBUG) Log.v(getTag(), "returning view " + view);
return view;
|
public android.view.View | onInterceptFocusSearch(android.view.View focused, int direction)
if (mFocusSearchDisabled) {
return focused;
}
return null;
|
public void | onItemsAdded(android.support.v7.widget.RecyclerView recyclerView, int positionStart, int itemCount)
if (DEBUG) Log.v(getTag(), "onItemsAdded positionStart "
+ positionStart + " itemCount " + itemCount);
if (mFocusPosition != NO_POSITION && mFocusPositionOffset != Integer.MIN_VALUE
&& getChildAt(mFocusPosition) != null) {
int pos = mFocusPosition + mFocusPositionOffset;
if (positionStart <= pos) {
mFocusPositionOffset += itemCount;
}
}
mChildrenStates.clear();
|
public void | onItemsChanged(android.support.v7.widget.RecyclerView recyclerView)
if (DEBUG) Log.v(getTag(), "onItemsChanged");
mFocusPositionOffset = 0;
mChildrenStates.clear();
|
public void | onItemsMoved(android.support.v7.widget.RecyclerView recyclerView, int fromPosition, int toPosition, int itemCount)
if (DEBUG) Log.v(getTag(), "onItemsMoved fromPosition "
+ fromPosition + " toPosition " + toPosition);
if (mFocusPosition != NO_POSITION && mFocusPositionOffset != Integer.MIN_VALUE
&& getChildAt(mFocusPosition) != null) {
int pos = mFocusPosition + mFocusPositionOffset;
if (fromPosition <= pos && pos < fromPosition + itemCount) {
// moved items include focused position
mFocusPositionOffset += toPosition - fromPosition;
} else if (fromPosition < pos && toPosition > pos - itemCount) {
// move items before focus position to after focused position
mFocusPositionOffset -= itemCount;
} else if (fromPosition > pos && toPosition < pos) {
// move items after focus position to before focused position
mFocusPositionOffset += itemCount;
}
}
mChildrenStates.clear();
|
public void | onItemsRemoved(android.support.v7.widget.RecyclerView recyclerView, int positionStart, int itemCount)
if (DEBUG) Log.v(getTag(), "onItemsRemoved positionStart "
+ positionStart + " itemCount " + itemCount);
if (mFocusPosition != NO_POSITION && mFocusPositionOffset != Integer.MIN_VALUE
&& getChildAt(mFocusPosition) != null) {
int pos = mFocusPosition + mFocusPositionOffset;
if (positionStart <= pos) {
if (positionStart + itemCount > pos) {
// stop updating offset after the focus item was removed
mFocusPositionOffset = Integer.MIN_VALUE;
} else {
mFocusPositionOffset -= itemCount;
}
}
}
mChildrenStates.clear();
|
public void | onItemsUpdated(android.support.v7.widget.RecyclerView recyclerView, int positionStart, int itemCount)
if (DEBUG) Log.v(getTag(), "onItemsUpdated positionStart "
+ positionStart + " itemCount " + itemCount);
for (int i = positionStart, end = positionStart + itemCount; i < end; i++) {
mChildrenStates.remove(i);
}
|
public void | onLayoutChildren(android.support.v7.widget.RecyclerView.Recycler recycler, android.support.v7.widget.RecyclerView.State state)
if (DEBUG) {
Log.v(getTag(), "layoutChildren start numRows " + mNumRows + " mScrollOffsetSecondary "
+ mScrollOffsetSecondary + " mScrollOffsetPrimary " + mScrollOffsetPrimary
+ " inPreLayout " + state.isPreLayout()
+ " didStructureChange " + state.didStructureChange()
+ " mForceFullLayout " + mForceFullLayout);
Log.v(getTag(), "width " + getWidth() + " height " + getHeight());
}
if (mNumRows == 0) {
// haven't done measure yet
return;
}
final int itemCount = state.getItemCount();
if (itemCount < 0) {
return;
}
if (!mLayoutEnabled) {
discardLayoutInfo();
removeAndRecycleAllViews(recycler);
return;
}
mInLayout = true;
final boolean scrollToFocus = !isSmoothScrolling()
&& mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_ALIGNED;
if (mFocusPosition != NO_POSITION && mFocusPositionOffset != Integer.MIN_VALUE) {
mFocusPosition = mFocusPosition + mFocusPositionOffset;
mFocusPositionOffset = 0;
}
saveContext(recycler, state);
// Track the old focus view so we can adjust our system scroll position
// so that any scroll animations happening now will remain valid.
// We must use same delta in Pre Layout (if prelayout exists) and second layout.
// So we cache the deltas in PreLayout and use it in second layout.
int delta = 0, deltaSecondary = 0;
if (mFocusPosition != NO_POSITION && scrollToFocus
&& mBaseGridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
// FIXME: we should get the remaining scroll animation offset from RecyclerView
View focusView = findViewByPosition(mFocusPosition);
if (focusView != null) {
delta = mWindowAlignment.mainAxis().getSystemScrollPos(mScrollOffsetPrimary
+ getViewCenter(focusView), false, false) - mScrollOffsetPrimary;
deltaSecondary = mWindowAlignment.secondAxis().getSystemScrollPos(
mScrollOffsetSecondary + getViewCenterSecondary(focusView),
false, false) - mScrollOffsetSecondary;
}
}
final boolean hasDoneFirstLayout = hasDoneFirstLayout();
int savedFocusPos = mFocusPosition;
boolean fastRelayout = false;
if (!mState.didStructureChange() && !mForceFullLayout && hasDoneFirstLayout) {
fastRelayout = true;
fastRelayout(scrollToFocus);
} else {
boolean hadFocus = mBaseGridView.hasFocus();
mFocusPosition = init(mFocusPosition);
if (mFocusPosition != savedFocusPos) {
if (DEBUG) Log.v(getTag(), "savedFocusPos " + savedFocusPos +
" mFocusPosition " + mFocusPosition);
}
if (mFocusPosition == NO_POSITION) {
mBaseGridView.clearFocus();
}
mWindowAlignment.mainAxis().invalidateScrollMin();
mWindowAlignment.mainAxis().invalidateScrollMax();
// depending on result of init(), either recreating everything
// or try to reuse the row start positions near mFocusPosition
if (mGrid.getSize() == 0) {
// this is a fresh creating all items, starting from
// mFocusPosition with a estimated row index.
mGrid.setStart(mFocusPosition, StaggeredGrid.START_DEFAULT);
// Can't track the old focus view
delta = deltaSecondary = 0;
} else {
// mGrid remembers Locations for the column that
// contains mFocusePosition and also mRows remembers start
// positions of each row.
// Manually re-create child views for that column
int firstIndex = mGrid.getFirstIndex();
int lastIndex = mGrid.getLastIndex();
for (int i = firstIndex; i <= lastIndex; i++) {
mGridProvider.createItem(i, mGrid.getLocation(i).row, true);
}
}
// add visible views at end until reach the end of window
appendVisibleItems();
// add visible views at front until reach the start of window
prependVisibleItems();
// multiple rounds: scrollToView of first round may drag first/last child into
// "visible window" and we update scrollMin/scrollMax then run second scrollToView
int oldFirstVisible;
int oldLastVisible;
do {
updateScrollMin();
updateScrollMax();
oldFirstVisible = mFirstVisiblePos;
oldLastVisible = mLastVisiblePos;
View focusView = findViewByPosition(mFocusPosition);
// we need force to initialize the child view's position
scrollToView(focusView, false);
if (focusView != null && hadFocus) {
focusView.requestFocus();
}
appendVisibleItems();
prependVisibleItems();
removeInvisibleViewsAtFront();
removeInvisibleViewsAtEnd();
} while (mFirstVisiblePos != oldFirstVisible || mLastVisiblePos != oldLastVisible);
}
mForceFullLayout = false;
if (scrollToFocus) {
scrollDirectionPrimary(-delta);
scrollDirectionSecondary(-deltaSecondary);
}
appendVisibleItems();
prependVisibleItems();
removeInvisibleViewsAtFront();
removeInvisibleViewsAtEnd();
if (DEBUG) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
mGrid.debugPrint(pw);
Log.d(getTag(), sw.toString());
}
if (mRowSecondarySizeRefresh) {
mRowSecondarySizeRefresh = false;
} else {
updateRowSecondarySizeRefresh();
}
if (fastRelayout && mFocusPosition != savedFocusPos) {
dispatchChildSelected();
}
mInLayout = false;
leaveContext();
if (DEBUG) Log.v(getTag(), "layoutChildren end");
|
public void | onMeasure(android.support.v7.widget.RecyclerView.Recycler recycler, android.support.v7.widget.RecyclerView.State state, int widthSpec, int heightSpec)
saveContext(recycler, state);
int sizePrimary, sizeSecondary, modeSecondary, paddingSecondary;
int measuredSizeSecondary;
if (mOrientation == HORIZONTAL) {
sizePrimary = MeasureSpec.getSize(widthSpec);
sizeSecondary = MeasureSpec.getSize(heightSpec);
modeSecondary = MeasureSpec.getMode(heightSpec);
paddingSecondary = getPaddingTop() + getPaddingBottom();
} else {
sizeSecondary = MeasureSpec.getSize(widthSpec);
sizePrimary = MeasureSpec.getSize(heightSpec);
modeSecondary = MeasureSpec.getMode(widthSpec);
paddingSecondary = getPaddingLeft() + getPaddingRight();
}
if (DEBUG) Log.v(getTag(), "onMeasure widthSpec " + Integer.toHexString(widthSpec) +
" heightSpec " + Integer.toHexString(heightSpec) +
" modeSecondary " + Integer.toHexString(modeSecondary) +
" sizeSecondary " + sizeSecondary + " " + this);
mMaxSizeSecondary = sizeSecondary;
if (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT) {
mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
mFixedRowSizeSecondary = 0;
if (mRowSizeSecondary == null || mRowSizeSecondary.length != mNumRows) {
mRowSizeSecondary = new int[mNumRows];
}
// Measure all current children and update cached row heights
processRowSizeSecondary(true);
switch (modeSecondary) {
case MeasureSpec.UNSPECIFIED:
measuredSizeSecondary = getSizeSecondary() + paddingSecondary;
break;
case MeasureSpec.AT_MOST:
measuredSizeSecondary = Math.min(getSizeSecondary() + paddingSecondary,
mMaxSizeSecondary);
break;
case MeasureSpec.EXACTLY:
measuredSizeSecondary = mMaxSizeSecondary;
break;
default:
throw new IllegalStateException("wrong spec");
}
} else {
switch (modeSecondary) {
case MeasureSpec.UNSPECIFIED:
if (mRowSizeSecondaryRequested == 0) {
if (mOrientation == HORIZONTAL) {
throw new IllegalStateException("Must specify rowHeight or view height");
} else {
throw new IllegalStateException("Must specify columnWidth or view width");
}
}
mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
measuredSizeSecondary = mFixedRowSizeSecondary * mNumRows + mMarginSecondary
* (mNumRows - 1) + paddingSecondary;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
if (mNumRowsRequested == 0 && mRowSizeSecondaryRequested == 0) {
mNumRows = 1;
mFixedRowSizeSecondary = sizeSecondary - paddingSecondary;
} else if (mNumRowsRequested == 0) {
mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
mNumRows = (sizeSecondary + mMarginSecondary)
/ (mRowSizeSecondaryRequested + mMarginSecondary);
} else if (mRowSizeSecondaryRequested == 0) {
mNumRows = mNumRowsRequested;
mFixedRowSizeSecondary = (sizeSecondary - paddingSecondary - mMarginSecondary
* (mNumRows - 1)) / mNumRows;
} else {
mNumRows = mNumRowsRequested;
mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
}
measuredSizeSecondary = sizeSecondary;
if (modeSecondary == MeasureSpec.AT_MOST) {
int childrenSize = mFixedRowSizeSecondary * mNumRows + mMarginSecondary
* (mNumRows - 1) + paddingSecondary;
if (childrenSize < measuredSizeSecondary) {
measuredSizeSecondary = childrenSize;
}
}
break;
default:
throw new IllegalStateException("wrong spec");
}
}
if (mOrientation == HORIZONTAL) {
setMeasuredDimension(sizePrimary, measuredSizeSecondary);
} else {
setMeasuredDimension(measuredSizeSecondary, sizePrimary);
}
if (DEBUG) {
Log.v(getTag(), "onMeasure sizePrimary " + sizePrimary +
" measuredSizeSecondary " + measuredSizeSecondary +
" mFixedRowSizeSecondary " + mFixedRowSizeSecondary +
" mNumRows " + mNumRows);
}
leaveContext();
|
public boolean | onRequestChildFocus(android.support.v7.widget.RecyclerView parent, android.view.View child, android.view.View focused)
if (mFocusSearchDisabled) {
return true;
}
if (getPositionByView(child) == NO_POSITION) {
// This shouldn't happen, but in case it does be sure not to attempt a
// scroll to a view whose item has been removed.
return true;
}
if (!mInLayout && !mInSelection) {
scrollToView(child, true);
}
return true;
|
public void | onRestoreInstanceState(android.os.Parcelable state)
if (!(state instanceof SavedState)) {
return;
}
SavedState loadingState = (SavedState)state;
mFocusPosition = loadingState.index;
mFocusPositionOffset = 0;
mChildrenStates.loadFromBundle(loadingState.childStates);
mForceFullLayout = true;
requestLayout();
if (DEBUG) Log.v(getTag(), "onRestoreInstanceState mFocusPosition " + mFocusPosition);
|
public void | onRtlPropertiesChanged(int layoutDirection)
if (mOrientation == HORIZONTAL) {
mReverseFlowPrimary = layoutDirection == View.LAYOUT_DIRECTION_RTL;
mReverseFlowSecondary = false;
} else {
mReverseFlowSecondary = layoutDirection == View.LAYOUT_DIRECTION_RTL;
mReverseFlowPrimary = false;
}
mWindowAlignment.horizontal.setReversedFlow(layoutDirection == View.LAYOUT_DIRECTION_RTL);
|
public android.os.Parcelable | onSaveInstanceState()
if (DEBUG) Log.v(getTag(), "onSaveInstanceState getSelection() " + getSelection());
SavedState ss = new SavedState();
for (int i = 0, count = getChildCount(); i < count; i++) {
View view = getChildAt(i);
int position = getPositionByView(view);
if (position != NO_POSITION) {
mChildrenStates.saveOnScreenView(view, position);
}
}
ss.index = getSelection();
ss.childStates = mChildrenStates.saveAsBundle();
return ss;
|
private boolean | prependOneVisibleItem()
while (true) {
if (mFirstVisiblePos > 0) {
if (mFirstVisiblePos > mGrid.getFirstIndex()) {
// prepend invisible view of saved location till first row
final int index = mFirstVisiblePos - 1;
final int row = mGrid.getLocation(index).row;
mGridProvider.createItem(index, row, false);
if (row == 0) {
return false;
}
} else {
if (mReverseFlowPrimary) {
mGrid.prependItems(mScrollOffsetPrimary + mSizePrimary);
} else {
mGrid.prependItems(mScrollOffsetPrimary);
}
return false;
}
} else {
return true;
}
}
|
private void | prependVisibleItems()
while (needsPrependVisibleItem()) {
if (prependOneVisibleItem()) {
break;
}
}
|
private boolean | processRowSizeSecondary(boolean measure)
if (mFixedRowSizeSecondary != 0) {
return false;
}
List<Integer>[] rows = mGrid == null ? null :
mGrid.getItemPositionsInRows(mFirstVisiblePos, mLastVisiblePos);
boolean changed = false;
int scrapChildWidth = -1;
int scrapChildHeight = -1;
for (int rowIndex = 0; rowIndex < mNumRows; rowIndex++) {
final int rowItemCount = rows == null ? 0 : rows[rowIndex].size();
if (DEBUG) Log.v(getTag(), "processRowSizeSecondary row " + rowIndex +
" rowItemCount " + rowItemCount);
int rowSize = -1;
for (int i = 0; i < rowItemCount; i++) {
final View view = findViewByPosition(rows[rowIndex].get(i));
if (view == null) {
continue;
}
if (measure && view.isLayoutRequested()) {
measureChild(view);
}
final int secondarySize = mOrientation == HORIZONTAL ?
view.getMeasuredHeight() : view.getMeasuredWidth();
if (secondarySize > rowSize) {
rowSize = secondarySize;
}
}
final int itemCount = mState.getItemCount();
if (measure && rowSize < 0 && itemCount > 0) {
if (scrapChildWidth < 0 && scrapChildHeight < 0) {
int position;
if (mFocusPosition == NO_POSITION) {
position = 0;
} else if (mFocusPosition >= itemCount) {
position = itemCount - 1;
} else {
position = mFocusPosition;
}
measureScrapChild(position,
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
scrapChildWidth = mMeasuredDimension[0];
scrapChildHeight = mMeasuredDimension[1];
if (DEBUG) Log.v(TAG, "measured scrap child: " + scrapChildWidth +
" " + scrapChildHeight);
}
rowSize = mOrientation == HORIZONTAL ? scrapChildHeight : scrapChildWidth;
}
if (rowSize < 0) {
rowSize = 0;
}
if (DEBUG) Log.v(getTag(), "row " + rowIndex + " rowItemCount " + rowItemCount +
" rowSize " + rowSize);
if (mRowSizeSecondary[rowIndex] != rowSize) {
if (DEBUG) Log.v(getTag(), "row size secondary changed: " + mRowSizeSecondary[rowIndex] +
", " + rowSize);
mRowSizeSecondary[rowIndex] = rowSize;
changed = true;
}
}
return changed;
|
public void | removeAndRecycleAllViews(android.support.v7.widget.RecyclerView.Recycler recycler)
if (DEBUG) Log.v(TAG, "removeAndRecycleAllViews " + getChildCount());
for (int i = getChildCount() - 1; i >= 0; i--) {
removeAndRecycleViewAt(i, recycler);
}
|
private void | removeChildAt(int position)
View v = findViewByPosition(position);
if (v != null) {
if (DEBUG) {
Log.d(getTag(), "removeAndRecycleViewAt " + position + " " + v);
}
mChildrenStates.saveOffscreenView(v, position);
removeAndRecycleView(v, mRecycler);
}
|
private void | removeInvisibleViewsAtEnd()
if (!mPruneChild) {
return;
}
boolean update = false;
while(mLastVisiblePos > mFirstVisiblePos && mLastVisiblePos > mFocusPosition) {
View view = findViewByPosition(mLastVisiblePos);
boolean offEnd = (!mReverseFlowPrimary) ? getViewMin(view) > mSizePrimary :
getViewMax(view) < 0;
if (offEnd) {
removeChildAt(mLastVisiblePos);
mLastVisiblePos--;
update = true;
} else {
break;
}
}
if (update) {
updateRowsMinMax();
}
|
private void | removeInvisibleViewsAtFront()
if (!mPruneChild) {
return;
}
boolean update = false;
while(mLastVisiblePos > mFirstVisiblePos && mFirstVisiblePos < mFocusPosition) {
View view = findViewByPosition(mFirstVisiblePos);
boolean offFront = (!mReverseFlowPrimary) ? getViewMax(view) < 0:
getViewMin(view) > mSizePrimary;
if (offFront) {
removeChildAt(mFirstVisiblePos);
mFirstVisiblePos++;
update = true;
} else {
break;
}
}
if (update) {
updateRowsMinMax();
}
|
public boolean | requestChildRectangleOnScreen(android.support.v7.widget.RecyclerView parent, android.view.View view, android.graphics.Rect rect, boolean immediate)
if (DEBUG) Log.v(getTag(), "requestChildRectangleOnScreen " + view + " " + rect);
return false;
|
private void | saveContext(android.support.v7.widget.RecyclerView.Recycler recycler, android.support.v7.widget.RecyclerView.State state)Save Recycler and State for convenience. Must be paired with leaveContext().
if (mRecycler != null || mState != null) {
Log.e(TAG, "Recycler information was not released, bug!");
}
mRecycler = recycler;
mState = state;
|
private int | scrollDirectionPrimary(int da)
boolean isMaxUnknown = false, isMinUnknown = false;
int minScroll = 0, maxScroll = 0;
if (da > 0) {
isMaxUnknown = mWindowAlignment.mainAxis().isMaxUnknown();
if (!isMaxUnknown) {
maxScroll = mWindowAlignment.mainAxis().getMaxScroll();
if (mScrollOffsetPrimary + da > maxScroll) {
da = maxScroll - mScrollOffsetPrimary;
}
}
} else if (da < 0) {
isMinUnknown = mWindowAlignment.mainAxis().isMinUnknown();
if (!isMinUnknown) {
minScroll = mWindowAlignment.mainAxis().getMinScroll();
if (mScrollOffsetPrimary + da < minScroll) {
da = minScroll - mScrollOffsetPrimary;
}
}
}
if (da == 0) {
return 0;
}
offsetChildrenPrimary(-da);
mScrollOffsetPrimary += da;
if (mInLayout) {
return da;
}
int childCount = getChildCount();
boolean updated;
if (da > 0) {
if (mReverseFlowPrimary) {
prependVisibleItems();
} else {
appendVisibleItems();
}
} else if (da < 0) {
if (mReverseFlowPrimary) {
appendVisibleItems();
} else {
prependVisibleItems();
}
}
updated = getChildCount() > childCount;
childCount = getChildCount();
if (da > 0) {
if (mReverseFlowPrimary) {
removeInvisibleViewsAtEnd();
} else {
removeInvisibleViewsAtFront();
}
} else if (da < 0) {
if (mReverseFlowPrimary) {
removeInvisibleViewsAtFront();
} else {
removeInvisibleViewsAtEnd();
}
}
updated |= getChildCount() < childCount;
if (updated) {
updateRowSecondarySizeRefresh();
}
mBaseGridView.invalidate();
return da;
|
private int | scrollDirectionSecondary(int dy)
if (dy == 0) {
return 0;
}
offsetChildrenSecondary(-dy);
mScrollOffsetSecondary += dy;
mBaseGridView.invalidate();
return dy;
|
private void | scrollGrid(int scrollPrimary, int scrollSecondary, boolean smooth)
if (mInLayout) {
scrollDirectionPrimary(scrollPrimary);
scrollDirectionSecondary(scrollSecondary);
} else {
int scrollX;
int scrollY;
if (mOrientation == HORIZONTAL) {
scrollX = scrollPrimary;
scrollY = scrollSecondary;
} else {
scrollX = scrollSecondary;
scrollY = scrollPrimary;
}
if (smooth) {
mBaseGridView.smoothScrollBy(scrollX, scrollY);
} else {
mBaseGridView.scrollBy(scrollX, scrollY);
}
}
|
public int | scrollHorizontallyBy(int dx, android.support.v7.widget.RecyclerView.Recycler recycler, android.support.v7.widget.RecyclerView.State state)
if (DEBUG) Log.v(getTag(), "scrollHorizontallyBy " + dx);
if (!mLayoutEnabled || !hasDoneFirstLayout()) {
return 0;
}
saveContext(recycler, state);
int result;
if (mOrientation == HORIZONTAL) {
result = scrollDirectionPrimary(dx);
} else {
result = scrollDirectionSecondary(dx);
}
leaveContext();
return result;
|
private void | scrollToSelection(android.support.v7.widget.RecyclerView parent, int position, boolean smooth)
View view = findViewByPosition(position);
if (view != null) {
mInSelection = true;
scrollToView(view, smooth);
mInSelection = false;
} else {
mFocusPosition = position;
mFocusPositionOffset = 0;
if (!mLayoutEnabled) {
return;
}
if (smooth) {
if (!hasDoneFirstLayout()) {
Log.w(getTag(), "setSelectionSmooth should " +
"not be called before first layout pass");
return;
}
LinearSmoothScroller linearSmoothScroller =
new LinearSmoothScroller(parent.getContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
if (getChildCount() == 0) {
return null;
}
final int firstChildPos = getPosition(getChildAt(0));
// TODO We should be able to deduce direction from bounds of current and target focus,
// rather than making assumptions about positions and directionality
final boolean isStart = mReverseFlowPrimary ? targetPosition > firstChildPos : targetPosition < firstChildPos;
final int direction = isStart ? -1 : 1;
if (mOrientation == HORIZONTAL) {
return new PointF(direction, 0);
} else {
return new PointF(0, direction);
}
}
@Override
protected void onTargetFound(View targetView,
RecyclerView.State state, Action action) {
if (hasFocus()) {
targetView.requestFocus();
}
dispatchChildSelected();
if (getScrollPosition(targetView, mTempDeltas)) {
int dx, dy;
if (mOrientation == HORIZONTAL) {
dx = mTempDeltas[0];
dy = mTempDeltas[1];
} else {
dx = mTempDeltas[1];
dy = mTempDeltas[0];
}
final int distance = (int) Math.sqrt(dx * dx + dy * dy);
final int time = calculateTimeForDeceleration(distance);
action.update(dx, dy, time, mDecelerateInterpolator);
}
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
} else {
mForceFullLayout = true;
parent.requestLayout();
}
}
|
private void | scrollToView(android.view.View view, boolean smooth)Scroll to a given child view and change mFocusPosition.
int newFocusPosition = getPositionByView(view);
if (newFocusPosition != mFocusPosition) {
mFocusPosition = newFocusPosition;
mFocusPositionOffset = 0;
if (!mInLayout) {
dispatchChildSelected();
}
}
if (mBaseGridView.isChildrenDrawingOrderEnabledInternal()) {
mBaseGridView.invalidate();
}
if (view == null) {
return;
}
if (!view.hasFocus() && mBaseGridView.hasFocus()) {
// transfer focus to the child if it does not have focus yet (e.g. triggered
// by setSelection())
view.requestFocus();
}
if (!mScrollEnabled) {
return;
}
if (getScrollPosition(view, mTempDeltas)) {
scrollGrid(mTempDeltas[0], mTempDeltas[1], smooth);
}
|
public int | scrollVerticallyBy(int dy, android.support.v7.widget.RecyclerView.Recycler recycler, android.support.v7.widget.RecyclerView.State state)
if (DEBUG) Log.v(getTag(), "scrollVerticallyBy " + dy);
if (!mLayoutEnabled || !hasDoneFirstLayout()) {
return 0;
}
saveContext(recycler, state);
int result;
if (mOrientation == VERTICAL) {
result = scrollDirectionPrimary(dy);
} else {
result = scrollDirectionSecondary(dy);
}
leaveContext();
return result;
|
void | setChildrenVisibility(int visiblity)
mChildVisibility = visiblity;
if (mChildVisibility != -1) {
int count = getChildCount();
for (int i= 0; i < count; i++) {
getChildAt(i).setVisibility(mChildVisibility);
}
}
|
public void | setFocusOutAllowed(boolean throughFront, boolean throughEnd)
mFocusOutFront = throughFront;
mFocusOutEnd = throughEnd;
|
public void | setFocusScrollStrategy(int focusScrollStrategy)
mFocusScrollStrategy = focusScrollStrategy;
|
void | setFocusSearchDisabled(boolean disabled)
mFocusSearchDisabled = disabled;
|
public void | setGravity(int gravity)
mGravity = gravity;
|
public void | setHorizontalMargin(int margin)
if (mOrientation == HORIZONTAL) {
mMarginPrimary = mHorizontalMargin = margin;
} else {
mMarginSecondary = mHorizontalMargin = margin;
}
|
public void | setItemAlignmentOffset(int alignmentOffset)
mItemAlignment.mainAxis().setItemAlignmentOffset(alignmentOffset);
updateChildAlignments();
|
public void | setItemAlignmentOffsetPercent(float offsetPercent)
mItemAlignment.mainAxis().setItemAlignmentOffsetPercent(offsetPercent);
updateChildAlignments();
|
public void | setItemAlignmentOffsetWithPadding(boolean withPadding)
mItemAlignment.mainAxis().setItemAlignmentOffsetWithPadding(withPadding);
updateChildAlignments();
|
public void | setItemAlignmentViewId(int viewId)
mItemAlignment.mainAxis().setItemAlignmentViewId(viewId);
updateChildAlignments();
|
public void | setItemMargin(int margin)
mVerticalMargin = mHorizontalMargin = margin;
mMarginPrimary = mMarginSecondary = margin;
|
public void | setLayoutEnabled(boolean layoutEnabled)
if (mLayoutEnabled != layoutEnabled) {
mLayoutEnabled = layoutEnabled;
requestLayout();
}
|
public void | setNumRows(int numRows)
if (numRows < 0) throw new IllegalArgumentException();
mNumRowsRequested = numRows;
mForceFullLayout = true;
|
public void | setOnChildSelectedListener(OnChildSelectedListener listener)
mChildSelectedListener = listener;
|
public void | setOrientation(int orientation)
if (orientation != HORIZONTAL && orientation != VERTICAL) {
if (DEBUG) Log.v(getTag(), "invalid orientation: " + orientation);
return;
}
mOrientation = orientation;
mWindowAlignment.setOrientation(orientation);
mItemAlignment.setOrientation(orientation);
mForceFullLayout = true;
|
public void | setPruneChild(boolean pruneChild)
if (mPruneChild != pruneChild) {
mPruneChild = pruneChild;
if (mPruneChild) {
requestLayout();
}
}
|
public void | setRowHeight(int height)Set the row height. May be WRAP_CONTENT, or a size in pixels.
if (height >= 0 || height == ViewGroup.LayoutParams.WRAP_CONTENT) {
mRowSizeSecondaryRequested = height;
} else {
throw new IllegalArgumentException("Invalid row height: " + height);
}
|
public void | setScrollEnabled(boolean scrollEnabled)
if (mScrollEnabled != scrollEnabled) {
mScrollEnabled = scrollEnabled;
if (mScrollEnabled && mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_ALIGNED
&& mFocusPosition != NO_POSITION) {
scrollToSelection(mBaseGridView, mFocusPosition, true);
}
}
|
public void | setSelection(android.support.v7.widget.RecyclerView parent, int position)
setSelection(parent, position, false);
|
public void | setSelection(android.support.v7.widget.RecyclerView parent, int position, boolean smooth)
if (mFocusPosition != position && position != NO_POSITION) {
scrollToSelection(parent, position, smooth);
}
|
public void | setSelectionSmooth(android.support.v7.widget.RecyclerView parent, int position)
setSelection(parent, position, true);
|
public void | setVerticalMargin(int margin)
if (mOrientation == HORIZONTAL) {
mMarginSecondary = mVerticalMargin = margin;
} else {
mMarginPrimary = mVerticalMargin = margin;
}
|
public void | setWindowAlignment(int windowAlignment)
mWindowAlignment.mainAxis().setWindowAlignment(windowAlignment);
|
public void | setWindowAlignmentOffset(int alignmentOffset)
mWindowAlignment.mainAxis().setWindowAlignmentOffset(alignmentOffset);
|
public void | setWindowAlignmentOffsetPercent(float offsetPercent)
mWindowAlignment.mainAxis().setWindowAlignmentOffsetPercent(offsetPercent);
|
private void | updateChildAlignments(android.view.View v)
LayoutParams p = (LayoutParams) v.getLayoutParams();
p.setAlignX(mItemAlignment.horizontal.getAlignmentPosition(v));
p.setAlignY(mItemAlignment.vertical.getAlignmentPosition(v));
|
private void | updateChildAlignments()
for (int i = 0, c = getChildCount(); i < c; i++) {
updateChildAlignments(getChildAt(i));
}
|
private void | updateChildOpticalInsets(android.view.View v, int left, int top, int right, int bottom)
LayoutParams p = (LayoutParams) v.getLayoutParams();
p.setOpticalInsets(left - v.getLeft(), top - v.getTop(),
v.getRight() - right, v.getBottom() - bottom);
|
private void | updateRowSecondarySizeRefresh()Checks if we need to update row secondary sizes.
mRowSecondarySizeRefresh = processRowSizeSecondary(false);
if (mRowSecondarySizeRefresh) {
if (DEBUG) Log.v(getTag(), "mRowSecondarySizeRefresh now set");
forceRequestLayout();
}
|
private void | updateRowsMinMax()
if (mFirstVisiblePos < 0) {
return;
}
for (int i = 0; i < mNumRows; i++) {
mRows[i].low = Integer.MAX_VALUE;
mRows[i].high = Integer.MIN_VALUE;
}
for (int i = mFirstVisiblePos; i <= mLastVisiblePos; i++) {
View view = findViewByPosition(i);
int row = mGrid.getLocation(i).row;
int low = getViewMin(view) + mScrollOffsetPrimary;
if (low < mRows[row].low) {
mRows[row].low = low;
}
int high = getViewMax(view) + mScrollOffsetPrimary;
if (high > mRows[row].high) {
mRows[row].high = high;
}
}
|
private void | updateScrollController()
// mScrollOffsetPrimary and mScrollOffsetSecondary includes the padding.
// e.g. when topPadding is 16 for horizontal grid view, the initial
// mScrollOffsetSecondary is -16. fastLayout() put views based on offsets(not padding),
// when padding changes to 20, we also need update mScrollOffsetSecondary to -20 before
// fastLayout() is performed
int paddingPrimaryDiff, paddingSecondaryDiff;
if (mOrientation == HORIZONTAL) {
paddingPrimaryDiff = getPaddingLeft() - mWindowAlignment.horizontal.getPaddingLow();
paddingSecondaryDiff = getPaddingTop() - mWindowAlignment.vertical.getPaddingLow();
} else {
paddingPrimaryDiff = getPaddingTop() - mWindowAlignment.vertical.getPaddingLow();
paddingSecondaryDiff = getPaddingLeft() - mWindowAlignment.horizontal.getPaddingLow();
}
mScrollOffsetPrimary -= paddingPrimaryDiff;
mScrollOffsetSecondary -= paddingSecondaryDiff;
mWindowAlignment.horizontal.setSize(getWidth());
mWindowAlignment.vertical.setSize(getHeight());
mWindowAlignment.horizontal.setPadding(getPaddingLeft(), getPaddingRight());
mWindowAlignment.vertical.setPadding(getPaddingTop(), getPaddingBottom());
mSizePrimary = mWindowAlignment.mainAxis().getSize();
if (DEBUG) {
Log.v(getTag(), "updateScrollController mSizePrimary " + mSizePrimary
+ " mWindowAlignment " + mWindowAlignment
+ " mScrollOffsetPrimary " + mScrollOffsetPrimary);
}
|
private void | updateScrollMax()
int highVisiblePos = (!mReverseFlowPrimary) ? mLastVisiblePos : mFirstVisiblePos;
int highMaxPos = (!mReverseFlowPrimary) ? mState.getItemCount() - 1 : 0;
if (highVisiblePos < 0) {
return;
}
final boolean highAvailable = highVisiblePos == highMaxPos;
final boolean maxUnknown = mWindowAlignment.mainAxis().isMaxUnknown();
if (!highAvailable && maxUnknown) {
return;
}
int maxEdge = Integer.MIN_VALUE;
int rowIndex = -1;
for (int i = 0; i < mRows.length; i++) {
if (mRows[i].high > maxEdge) {
maxEdge = mRows[i].high;
rowIndex = i;
}
}
int maxScroll = Integer.MAX_VALUE;
for (int i = mFirstVisiblePos; i <= mLastVisiblePos; i++) {
int pos = mReverseFlowPrimary ? i : mLastVisiblePos-i+mFirstVisiblePos;
StaggeredGrid.Location location = mGrid.getLocation(pos);
if (location != null && location.row == rowIndex) {
int savedMaxEdge = mWindowAlignment.mainAxis().getMaxEdge();
mWindowAlignment.mainAxis().setMaxEdge(maxEdge);
maxScroll = getPrimarySystemScrollPosition(findViewByPosition(pos));
mWindowAlignment.mainAxis().setMaxEdge(savedMaxEdge);
break;
}
}
if (highAvailable) {
mWindowAlignment.mainAxis().setMaxEdge(maxEdge);
mWindowAlignment.mainAxis().setMaxScroll(maxScroll);
if (DEBUG) Log.v(getTag(), "updating scroll maxEdge to " + maxEdge +
" scrollMax to " + maxScroll);
} else {
// the maxScroll for currently last visible item is larger,
// so we must invalidate the max scroll value.
if (maxScroll > mWindowAlignment.mainAxis().getMaxScroll()) {
mWindowAlignment.mainAxis().invalidateScrollMax();
if (DEBUG) Log.v(getTag(), "Invalidate scrollMax since it should be "
+ "greater than " + maxScroll);
}
}
|
private void | updateScrollMin()
int lowVisiblePos = (!mReverseFlowPrimary) ? mFirstVisiblePos : mLastVisiblePos;
int lowMinPos = (!mReverseFlowPrimary) ? 0 : mState.getItemCount() - 1;
if (lowVisiblePos < 0) {
return;
}
final boolean lowAvailable = lowVisiblePos == lowMinPos;
final boolean minUnknown = mWindowAlignment.mainAxis().isMinUnknown();
if (!lowAvailable && minUnknown) {
return;
}
int minEdge = Integer.MAX_VALUE;
int rowIndex = -1;
for (int i = 0; i < mRows.length; i++) {
if (mRows[i].low < minEdge) {
minEdge = mRows[i].low;
rowIndex = i;
}
}
int minScroll = Integer.MIN_VALUE;
for (int i = mFirstVisiblePos; i <= mLastVisiblePos; i++) {
int pos = mReverseFlowPrimary ? mLastVisiblePos-i+mFirstVisiblePos : i;
StaggeredGrid.Location location = mGrid.getLocation(pos);
if (location != null && location.row == rowIndex) {
int savedMinEdge = mWindowAlignment.mainAxis().getMinEdge();
mWindowAlignment.mainAxis().setMinEdge(minEdge);
minScroll = getPrimarySystemScrollPosition(findViewByPosition(pos));
mWindowAlignment.mainAxis().setMinEdge(savedMinEdge);
break;
}
}
if (lowAvailable) {
mWindowAlignment.mainAxis().setMinEdge(minEdge);
mWindowAlignment.mainAxis().setMinScroll(minScroll);
if (DEBUG) Log.v(getTag(), "updating scroll minEdge to " + minEdge +
" scrollMin to " + minScroll);
} else {
// the minScroll for currently first visible item is smaller,
// so we must invalidate the min scroll value.
if (minScroll < mWindowAlignment.mainAxis().getMinScroll()) {
mWindowAlignment.mainAxis().invalidateScrollMin();
if (DEBUG) Log.v(getTag(), "Invalidate scrollMin, since it should be "
+ "less than " + minScroll);
}
}
|
private void | updateScrollSecondAxis()
mWindowAlignment.secondAxis().setMinEdge(0);
mWindowAlignment.secondAxis().setMaxEdge(getSizeSecondary());
|