use of android.support.v7.widget.RecyclerView.Recycler in project vlayout by alibaba.
the class FloatLayoutHelper method layoutViews.
@Override
public void layoutViews(RecyclerView.Recycler recycler, RecyclerView.State state, VirtualLayoutManager.LayoutStateWrapper layoutState, LayoutChunkResult result, final LayoutManagerHelper helper) {
// reach the end of this layout
if (isOutOfRange(layoutState.getCurrentPosition())) {
return;
}
// find view in currentPosition
View view = mFixView;
if (view == null)
view = layoutState.next(recycler);
else {
layoutState.skipCurrentPosition();
}
if (view == null) {
result.mFinished = true;
return;
}
helper.getChildViewHolder(view).setIsRecyclable(false);
mDoNormalHandle = state.isPreLayout();
if (mDoNormalHandle) {
// in PreLayout do normal layout
helper.addChildView(layoutState, view);
}
mFixView = view;
mFixView.setClickable(true);
doMeasureAndLayout(view, helper);
result.mConsumed = 0;
result.mIgnoreConsumed = true;
handleStateOnResult(result, view);
}
use of android.support.v7.widget.RecyclerView.Recycler in project vlayout by alibaba.
the class GridLayoutHelper method layoutViews.
@Override
public void layoutViews(RecyclerView.Recycler recycler, RecyclerView.State state, LayoutStateWrapper layoutState, LayoutChunkResult result, LayoutManagerHelper helper) {
// reach the end of this layout
if (isOutOfRange(layoutState.getCurrentPosition())) {
return;
}
boolean isStartLine = false, isEndLine = false;
final int currentPosition = layoutState.getCurrentPosition();
final int itemDirection = layoutState.getItemDirection();
final boolean layingOutInPrimaryDirection = itemDirection == LayoutStateWrapper.ITEM_DIRECTION_TAIL;
OrientationHelper orientationHelper = helper.getMainOrientationHelper();
final boolean layoutInVertical = helper.getOrientation() == VERTICAL;
if (layoutInVertical) {
mTotalSize = helper.getContentWidth() - helper.getPaddingRight() - helper.getPaddingLeft() - getHorizontalMargin() - getHorizontalPadding();
mSizePerSpan = (int) ((mTotalSize - (mSpanCount - 1) * mHGap) * 1.0f / mSpanCount + 0.5f);
} else {
mTotalSize = helper.getContentHeight() - helper.getPaddingBottom() - helper.getPaddingTop() - getVerticalMargin() - getVerticalPadding();
mSizePerSpan = (int) ((mTotalSize - (mSpanCount - 1) * mVGap) * 1.0f / mSpanCount + 0.5f);
}
int count = 0;
int consumedSpanCount = 0;
int remainingSpan = mSpanCount;
ensureSpanCount();
if (!layingOutInPrimaryDirection) {
// fill the remaining spacing this row
int itemSpanIndex = getSpanIndex(recycler, state, layoutState.getCurrentPosition());
int itemSpanSize = getSpanSize(recycler, state, layoutState.getCurrentPosition());
remainingSpan = itemSpanIndex + itemSpanSize;
// should find the last element of this row
if (itemSpanIndex != mSpanCount - 1) {
int index = layoutState.getCurrentPosition();
int revRemainingSpan = mSpanCount - remainingSpan;
while (count < mSpanCount && revRemainingSpan > 0) {
// go reverse direction to find views fill current row
index -= itemDirection;
if (isOutOfRange(index)) {
break;
}
final int spanSize = getSpanSize(recycler, state, index);
if (spanSize > mSpanCount) {
throw new IllegalArgumentException("Item at position " + index + " requires " + spanSize + " spans but GridLayoutManager has only " + mSpanCount + " spans.");
}
View view = layoutState.retrieve(recycler, index);
if (view == null)
break;
if (!isStartLine) {
isStartLine = helper.getReverseLayout() ? index == getRange().getUpper() : index == getRange().getLower();
}
if (!isEndLine) {
isEndLine = helper.getReverseLayout() ? index == getRange().getLower() : index == getRange().getUpper();
}
revRemainingSpan -= spanSize;
if (revRemainingSpan < 0)
break;
consumedSpanCount += spanSize;
mSet[count] = view;
count++;
}
if (count > 0) {
// reverse array
int s = 0, e = count - 1;
while (s < e) {
View temp = mSet[s];
mSet[s] = mSet[e];
mSet[e] = temp;
s++;
e--;
}
}
}
}
while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) {
int pos = layoutState.getCurrentPosition();
if (isOutOfRange(pos)) {
if (DEBUG)
Log.d(TAG, "pos [" + pos + "] is out of range");
break;
}
final int spanSize = getSpanSize(recycler, state, pos);
if (spanSize > mSpanCount) {
throw new IllegalArgumentException("Item at position " + pos + " requires " + spanSize + " spans but GridLayoutManager has only " + mSpanCount + " spans.");
}
remainingSpan -= spanSize;
if (remainingSpan < 0) {
// item did not fit into this row or column
break;
}
View view = layoutState.next(recycler);
if (view == null) {
break;
}
if (!isStartLine) {
isStartLine = helper.getReverseLayout() ? pos == getRange().getUpper().intValue() : pos == getRange().getLower().intValue();
}
if (!isEndLine) {
isEndLine = helper.getReverseLayout() ? pos == getRange().getLower().intValue() : pos == getRange().getUpper().intValue();
}
consumedSpanCount += spanSize;
mSet[count] = view;
count++;
}
if (count == 0) {
return;
}
int maxSize = 0;
// we should assign spans before item decor offsets are calculated
assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection, helper);
if (remainingSpan > 0 && mIsAutoExpand) {
if (layoutInVertical) {
mSizePerSpan = (helper.getContentWidth() - helper.getPaddingRight() - getHorizontalMargin() - getHorizontalPadding() - helper.getPaddingLeft() - (count - 1) * mHGap) / count;
} else {
mSizePerSpan = (helper.getContentHeight() - helper.getPaddingBottom() - getVerticalMargin() - getVerticalPadding() - helper.getPaddingTop() - (count - 1) * mVGap) / count;
}
}
boolean weighted = false;
if (mWeights != null && mWeights.length > 0) {
weighted = true;
int totalSpace;
if (layoutInVertical) {
totalSpace = helper.getContentWidth() - helper.getPaddingLeft() - helper.getPaddingRight() - getHorizontalMargin() - getHorizontalPadding() - (count - 1) * mHGap;
} else {
totalSpace = helper.getContentHeight() - helper.getPaddingTop() - helper.getPaddingBottom() - getVerticalMargin() - getVerticalPadding() - (count - 1) * mVGap;
}
// calculate width with weight in percentage
int eqCnt = 0, remainingSpace = totalSpace;
int colCnt = (remainingSpan > 0 && mIsAutoExpand) ? count : mSpanCount;
for (int i = 0; i < colCnt; i++) {
if (i < mWeights.length && !Float.isNaN(mWeights[i]) && mWeights[i] >= 0) {
float weight = mWeights[i];
mSpanCols[i] = (int) (weight * 1.0f / 100 * totalSpace + 0.5f);
remainingSpace -= mSpanCols[i];
} else {
eqCnt++;
mSpanCols[i] = -1;
}
}
if (eqCnt > 0) {
int eqLength = remainingSpace / eqCnt;
for (int i = 0; i < colCnt; i++) {
if (mSpanCols[i] < 0) {
mSpanCols[i] = eqLength;
}
}
}
}
for (int i = 0; i < count; i++) {
View view = mSet[i];
helper.addChildView(layoutState, view, layingOutInPrimaryDirection ? -1 : 0);
int spanSize = getSpanSize(recycler, state, helper.getPosition(view)), spec;
if (weighted) {
final int index = mSpanIndices[i];
int spanLength = 0;
for (int j = 0; j < spanSize; j++) {
spanLength += mSpanCols[j + index];
}
spec = View.MeasureSpec.makeMeasureSpec(Math.max(0, spanLength), View.MeasureSpec.EXACTLY);
} else {
spec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan * spanSize + Math.max(0, spanSize - 1) * (layoutInVertical ? mHGap : mVGap), View.MeasureSpec.EXACTLY);
}
final VirtualLayoutManager.LayoutParams lp = (VirtualLayoutManager.LayoutParams) view.getLayoutParams();
if (helper.getOrientation() == VERTICAL) {
helper.measureChild(view, spec, getMainDirSpec(lp.height, mTotalSize, View.MeasureSpec.getSize(spec), lp.mAspectRatio));
} else {
helper.measureChild(view, getMainDirSpec(lp.width, mTotalSize, View.MeasureSpec.getSize(spec), lp.mAspectRatio), View.MeasureSpec.getSize(spec));
}
final int size = orientationHelper.getDecoratedMeasurement(view);
if (size > maxSize) {
maxSize = size;
}
}
// views that did not measure the maxSize has to be re-measured
final int maxMeasureSpec = getMainDirSpec(maxSize, mTotalSize, 0, Float.NaN);
for (int i = 0; i < count; i++) {
final View view = mSet[i];
if (orientationHelper.getDecoratedMeasurement(view) != maxSize) {
int spanSize = getSpanSize(recycler, state, helper.getPosition(view)), spec;
if (weighted) {
final int index = mSpanIndices[i];
int spanLength = 0;
for (int j = 0; j < spanSize; j++) {
spanLength += mSpanCols[j + index];
}
spec = View.MeasureSpec.makeMeasureSpec(Math.max(0, spanLength), View.MeasureSpec.EXACTLY);
} else {
spec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan * spanSize + Math.max(0, spanSize - 1) * (layoutInVertical ? mHGap : mVGap), View.MeasureSpec.EXACTLY);
}
if (helper.getOrientation() == VERTICAL) {
helper.measureChild(view, spec, maxMeasureSpec);
} else {
helper.measureChild(view, maxMeasureSpec, spec);
}
}
}
int startSpace = 0, endSpace = 0;
if (isStartLine) {
startSpace = layoutInVertical ? mMarginTop + mPaddingTop : mMarginLeft + mPaddingLeft;
}
if (isEndLine) {
endSpace = layoutInVertical ? mMarginBottom + mPaddingBottom : mMarginRight + mPaddingRight;
}
result.mConsumed = maxSize + startSpace + endSpace;
final boolean layoutStart = layoutState.getLayoutDirection() == LayoutStateWrapper.LAYOUT_START;
if (!mLayoutWithAnchor && (!isEndLine || !layoutStart) && (!isStartLine || layoutStart)) {
result.mConsumed += (layoutInVertical ? mVGap : mHGap);
}
int left = 0, right = 0, top = 0, bottom = 0;
if (layoutInVertical) {
if (layoutState.getLayoutDirection() == LayoutStateWrapper.LAYOUT_START) {
bottom = layoutState.getOffset() - endSpace - ((mLayoutWithAnchor || isEndLine) ? 0 : mVGap);
top = bottom - maxSize;
} else {
top = layoutState.getOffset() + startSpace + ((mLayoutWithAnchor || isStartLine) ? 0 : mVGap);
bottom = top + maxSize;
}
} else {
if (layoutState.getLayoutDirection() == LayoutStateWrapper.LAYOUT_START) {
right = layoutState.getOffset() - endSpace - (mLayoutWithAnchor || isEndLine ? 0 : mHGap);
left = right - maxSize;
} else {
left = layoutState.getOffset() + startSpace + (mLayoutWithAnchor || isStartLine ? 0 : mHGap);
right = left + maxSize;
}
}
for (int i = 0; i < count; i++) {
View view = mSet[i];
final int index = mSpanIndices[i];
LayoutParams params = (LayoutParams) view.getLayoutParams();
if (layoutInVertical) {
if (weighted) {
left = helper.getPaddingLeft() + mMarginLeft + mPaddingLeft;
for (int j = 0; j < index; j++) left += mSpanCols[j] + mHGap;
} else
left = helper.getPaddingLeft() + mMarginLeft + mPaddingLeft + mSizePerSpan * index + index * mHGap;
right = left + orientationHelper.getDecoratedMeasurementInOther(view);
} else {
if (weighted) {
top = helper.getPaddingTop() + mMarginTop + mPaddingTop;
for (int j = 0; j < index; j++) top += mSpanCols[j] + mVGap;
} else
top = helper.getPaddingTop() + mMarginTop + mPaddingTop + mSizePerSpan * index + index * mVGap;
bottom = top + orientationHelper.getDecoratedMeasurementInOther(view);
}
if (DEBUG) {
Log.d(TAG, "layout item in position: " + params.getViewPosition() + " with text " + ((TextView) view).getText() + " with SpanIndex: " + index + " into (" + left + ", " + top + ", " + right + ", " + bottom + " )");
}
// We calculate everything with View's bounding box (which includes decor and margins)
// To calculate correct layout position, we subtract margins.
// modified by huifeng at 20160907, margins are already subtracted
layoutChild(view, left, top, right, bottom, helper);
// Consume the available space if the view is not removed OR changed
if (params.isItemRemoved() || params.isItemChanged()) {
result.mIgnoreConsumed = true;
}
result.mFocusable |= view.isFocusable();
}
mLayoutWithAnchor = false;
Arrays.fill(mSet, null);
Arrays.fill(mSpanIndices, 0);
Arrays.fill(mSpanCols, 0);
}
use of android.support.v7.widget.RecyclerView.Recycler in project vlayout by alibaba.
the class StaggeredGridLayoutHelper method recycleFromStart.
private void recycleFromStart(RecyclerView.Recycler recycler, int line, LayoutManagerHelper helper) {
final OrientationHelper orientationHelper = helper.getMainOrientationHelper();
boolean changed = true;
while (helper.getChildCount() > 0 && changed) {
View child = helper.getChildAt(0);
if (child != null && orientationHelper.getDecoratedEnd(child) < line) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int position = lp.getViewPosition();
Span span = findSpan(position, child, true);
if (span != null) {
span.popStart(orientationHelper);
helper.removeChildView(child);
recycler.recycleView(child);
} else {
changed = false;
}
} else {
// done
return;
}
}
}
use of android.support.v7.widget.RecyclerView.Recycler in project vlayout by alibaba.
the class StaggeredGridLayoutHelper method recycle.
private void recycle(RecyclerView.Recycler recycler, LayoutStateWrapper layoutState, Span updatedSpan, int recycleLine, LayoutManagerHelper helper) {
OrientationHelper orientation = helper.getMainOrientationHelper();
if (layoutState.getLayoutDirection() == LAYOUT_START) {
// calculate recycle line
int maxStart = getMaxStart(updatedSpan.getStartLine(orientation), orientation);
recycleFromEnd(recycler, Math.max(recycleLine, maxStart) + (orientation.getEnd() - orientation.getStartAfterPadding()), helper);
} else {
// calculate recycle line
int minEnd = getMinEnd(updatedSpan.getEndLine(orientation), orientation);
recycleFromStart(recycler, Math.min(recycleLine, minEnd) - (orientation.getEnd() - orientation.getStartAfterPadding()), helper);
}
}
use of android.support.v7.widget.RecyclerView.Recycler in project vlayout by alibaba.
the class StaggeredGridLayoutHelper method layoutViews.
@Override
public void layoutViews(RecyclerView.Recycler recycler, RecyclerView.State state, LayoutStateWrapper layoutState, LayoutChunkResult result, LayoutManagerHelper helper) {
if (isOutOfRange(layoutState.getCurrentPosition())) {
return;
}
ensureLanes();
final boolean layoutInVertical = helper.getOrientation() == VERTICAL;
final OrientationHelper orientationHelper = helper.getMainOrientationHelper();
final OrientationHelper secondaryOrientationHelper = helper.getSecondaryOrientationHelper();
mRemainingSpans.set(0, mNumLanes, true);
final int targetLine;
final int recycleLine;
// Line of the furthest row.
if (layoutState.getLayoutDirection() == LAYOUT_END) {
// ignore padding for recycler
recycleLine = layoutState.getOffset() + layoutState.getAvailable();
targetLine = recycleLine + layoutState.getExtra() + orientationHelper.getEndPadding();
} else {
// LAYOUT_START
// ignore padding for recycler
recycleLine = layoutState.getOffset() - layoutState.getAvailable();
targetLine = recycleLine - layoutState.getExtra() - orientationHelper.getStartAfterPadding();
}
updateAllRemainingSpans(layoutState.getLayoutDirection(), targetLine, orientationHelper);
final int defaultNewViewLine = layoutState.getOffset();
while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty() && !isOutOfRange(layoutState.getCurrentPosition())) {
boolean isStartLine = false, isEndLine = false;
View view = layoutState.next(recycler);
if (view == null)
break;
VirtualLayoutManager.LayoutParams lp = (VirtualLayoutManager.LayoutParams) view.getLayoutParams();
// find the span to put the view
final int position = lp.getViewPosition();
final int spanIndex = mLazySpanLookup.getSpan(position);
Span currentSpan;
boolean assignSpan = spanIndex == INVALID_SPAN_ID;
if (assignSpan) {
currentSpan = getNextSpan(defaultNewViewLine, layoutState, helper);
mLazySpanLookup.setSpan(position, currentSpan);
} else {
currentSpan = mSpans[spanIndex];
}
// handle margin for start/end line
isStartLine = position - getRange().getLower() < mNumLanes;
isEndLine = getRange().getUpper() - position - 1 < mNumLanes;
helper.addChildView(layoutState, view);
if (layoutInVertical) {
int widthSpec = helper.getChildMeasureSpec(mColLength, lp.width, false);
int heightSpec = helper.getChildMeasureSpec(orientationHelper.getTotalSpace(), Float.isNaN(lp.mAspectRatio) ? lp.height : (int) (View.MeasureSpec.getSize(widthSpec) / lp.mAspectRatio + 0.5f), true);
helper.measureChild(view, widthSpec, heightSpec);
} else {
int heightSpec = helper.getChildMeasureSpec(mColLength, lp.height, false);
int widthSpec = helper.getChildMeasureSpec(orientationHelper.getTotalSpace(), Float.isNaN(lp.mAspectRatio) ? lp.width : (int) (View.MeasureSpec.getSize(heightSpec) * lp.mAspectRatio + 0.5f), true);
helper.measureChild(view, widthSpec, heightSpec);
}
int start;
int end;
if (layoutState.getLayoutDirection() == LAYOUT_END) {
start = currentSpan.getEndLine(defaultNewViewLine, orientationHelper);
if (isStartLine)
start += layoutInVertical ? mMarginTop + mPaddingTop : mMarginLeft + mPaddingLeft;
else
start += (layoutInVertical ? mVGap : mHGap);
end = start + orientationHelper.getDecoratedMeasurement(view);
} else {
if (isEndLine)
end = currentSpan.getStartLine(defaultNewViewLine, orientationHelper) - (layoutInVertical ? mMarginBottom + mPaddingRight : mMarginRight + mPaddingRight);
else
end = currentSpan.getStartLine(defaultNewViewLine, orientationHelper) - (layoutInVertical ? mVGap : mHGap);
start = end - orientationHelper.getDecoratedMeasurement(view);
}
// lp.mSpan = currentSpan;
if (layoutState.getLayoutDirection() == LAYOUT_END) {
currentSpan.appendToSpan(view, orientationHelper);
} else {
currentSpan.prependToSpan(view, orientationHelper);
}
// left, right in vertical layout
int otherStart = ((currentSpan.mIndex == mNumLanes - 1) ? currentSpan.mIndex * (mColLength + mEachGap) - mEachGap + mLastGap : currentSpan.mIndex * (mColLength + mEachGap)) + secondaryOrientationHelper.getStartAfterPadding();
if (layoutInVertical) {
otherStart += mMarginLeft + mPaddingLeft;
} else {
otherStart += mMarginTop + mPaddingTop;
}
int otherEnd = otherStart + orientationHelper.getDecoratedMeasurementInOther(view);
if (layoutInVertical) {
layoutChild(view, otherStart, start, otherEnd, end, helper);
} else {
layoutChild(view, start, otherStart, end, otherEnd, helper);
}
updateRemainingSpans(currentSpan, layoutState.getLayoutDirection(), targetLine, orientationHelper);
recycle(recycler, layoutState, currentSpan, recycleLine, helper);
handleStateOnResult(result, view);
}
if (isOutOfRange(layoutState.getCurrentPosition())) {
// TODO: how to retain gap
if (layoutState.getLayoutDirection() == LayoutStateWrapper.LAYOUT_START) {
for (Span span : mSpans) {
if (span.mCachedStart != INVALID_LINE) {
span.mLastEdgeStart = span.mCachedStart;
}
}
} else {
for (Span span : mSpans) {
if (span.mCachedEnd != INVALID_LINE) {
span.mLastEdgeEnd = span.mCachedEnd;
}
}
}
}
if (layoutState.getLayoutDirection() == LayoutStateWrapper.LAYOUT_START) {
if (!isOutOfRange(layoutState.getCurrentPosition()) && layoutState.hasMore(state)) {
final int maxStart = getMaxStart(orientationHelper.getStartAfterPadding(), orientationHelper);
result.mConsumed = layoutState.getOffset() - maxStart;
} else {
final int minStart = getMinStart(orientationHelper.getEndAfterPadding(), orientationHelper);
result.mConsumed = layoutState.getOffset() - minStart + (layoutInVertical ? mMarginTop + mPaddingTop : mMarginLeft + mPaddingLeft);
}
} else {
if (!isOutOfRange(layoutState.getCurrentPosition()) && layoutState.hasMore(state)) {
final int minEnd = getMinEnd(orientationHelper.getEndAfterPadding(), orientationHelper);
result.mConsumed = minEnd - layoutState.getOffset();
} else {
final int maxEnd = getMaxEnd(orientationHelper.getEndAfterPadding(), orientationHelper);
result.mConsumed = maxEnd - layoutState.getOffset() + (layoutInVertical ? mMarginBottom + mPaddingBottom : mMarginRight + mPaddingRight);
}
}
}
Aggregations