use of com.alibaba.android.vlayout.OrientationHelperEx 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 OrientationHelperEx orientationHelper = helper.getMainOrientationHelper();
final OrientationHelperEx secondaryOrientationHelper = helper.getSecondaryOrientationHelper();
final boolean isOverLapMargin = helper.isEnableMarginOverLap();
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();
prelayoutViewList.clear();
while (layoutState.hasMore(state) && !mRemainingSpans.isEmpty() && !isOutOfRange(layoutState.getCurrentPosition())) {
boolean isStartLine = false, isEndLine = false;
int currentPosition = layoutState.getCurrentPosition();
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;
// fix the end line condition, edit by longerian
isEndLine = getRange().getUpper() - position < mNumLanes;
if (layoutState.isPreLayout()) {
prelayoutViewList.add(view);
}
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.measureChildWithMargins(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.measureChildWithMargins(view, widthSpec, heightSpec);
}
int start;
int end;
if (layoutState.getLayoutDirection() == LAYOUT_END) {
start = currentSpan.getEndLine(defaultNewViewLine, orientationHelper);
if (isStartLine) {
start += computeStartSpace(helper, layoutInVertical, true, isOverLapMargin);
} else {
if (mLayoutWithAnchor) {
if (Math.abs(currentPosition - anchorPosition) < mNumLanes) {
// do not add extra gaps here
} else {
start += (layoutInVertical ? mVGap : mHGap);
}
} else {
start += (layoutInVertical ? mVGap : mHGap);
}
}
end = start + orientationHelper.getDecoratedMeasurement(view);
} else {
if (isEndLine) {
end = currentSpan.getStartLine(defaultNewViewLine, orientationHelper) - (layoutInVertical ? mMarginBottom + mPaddingRight : mMarginRight + mPaddingRight);
// Log.d(TAG, "endLine " + position + " " + end);
} else {
end = currentSpan.getStartLine(defaultNewViewLine, orientationHelper) - (layoutInVertical ? mVGap : mHGap);
// Log.d(TAG, "normalEndLine " + position + " " + end);
}
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) {
layoutChildWithMargin(view, otherStart, start, otherEnd, end, helper);
} else {
layoutChildWithMargin(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()) && mSpans != null) {
// TODO: how to retain gap
if (layoutState.getLayoutDirection() == LayoutStateWrapper.LAYOUT_START) {
for (int i = 0, size = mSpans.length; i < size; i++) {
Span span = mSpans[i];
if (span.mCachedStart != INVALID_LINE) {
span.mLastEdgeStart = span.mCachedStart;
}
}
} else {
for (int i = 0, size = mSpans.length; i < size; i++) {
Span span = mSpans[i];
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);
}
}
recycleForPreLayout(recycler, layoutState, helper);
}
use of com.alibaba.android.vlayout.OrientationHelperEx in project vlayout by alibaba.
the class StaggeredGridLayoutHelper method recycleForPreLayout.
private void recycleForPreLayout(RecyclerView.Recycler recycler, LayoutStateWrapper layoutState, LayoutManagerHelper helper) {
final OrientationHelperEx orientationHelper = helper.getMainOrientationHelper();
for (int i = prelayoutViewList.size() - 1; i >= 0; i--) {
View child = prelayoutViewList.get(i);
if (child != null && orientationHelper.getDecoratedStart(child) > orientationHelper.getEndAfterPadding()) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int position = lp.getViewPosition();
Span span = findSpan(position, child, false);
if (span != null) {
span.popEnd(orientationHelper);
}
helper.removeChildView(child);
recycler.recycleView(child);
} else {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int position = lp.getViewPosition();
Span span = findSpan(position, child, false);
if (span != null) {
span.popEnd(orientationHelper);
}
helper.removeChildView(child);
recycler.recycleView(child);
break;
}
}
}
use of com.alibaba.android.vlayout.OrientationHelperEx in project vlayout by alibaba.
the class StaggeredGridLayoutHelper method recycle.
private void recycle(RecyclerView.Recycler recycler, LayoutStateWrapper layoutState, Span updatedSpan, int recycleLine, LayoutManagerHelper helper) {
OrientationHelperEx 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 com.alibaba.android.vlayout.OrientationHelperEx 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 boolean isOverLapMargin = helper.isEnableMarginOverLap();
final int itemDirection = layoutState.getItemDirection();
final boolean layingOutInPrimaryDirection = itemDirection == LayoutStateWrapper.ITEM_DIRECTION_TAIL;
OrientationHelperEx 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 && (count == consumedSpanCount) && mIsAutoExpand) {
// autoExpand only support when each cell occupy one span.
if (layoutInVertical) {
mSizePerSpan = (mTotalSize - (count - 1) * mHGap) / count;
} else {
mSizePerSpan = (mTotalSize - (count - 1) * mVGap) / count;
}
} else if (!layingOutInPrimaryDirection && remainingSpan == 0 && (count == consumedSpanCount) && mIsAutoExpand) {
// autoExpand only support when each cell occupy one span.
if (layoutInVertical) {
mSizePerSpan = (mTotalSize - (count - 1) * mHGap) / count;
} else {
mSizePerSpan = (mTotalSize - (count - 1) * mVGap) / count;
}
}
boolean weighted = false;
if (mWeights != null && mWeights.length > 0) {
weighted = true;
int totalSpace;
if (layoutInVertical) {
totalSpace = mTotalSize - (count - 1) * mHGap;
} else {
totalSpace = mTotalSize - (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.measureChildWithMargins(view, spec, getMainDirSpec(lp.height, mTotalSize, View.MeasureSpec.getSize(spec), lp.mAspectRatio));
} else {
helper.measureChildWithMargins(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.measureChildWithMargins(view, spec, maxMeasureSpec);
} else {
helper.measureChildWithMargins(view, maxMeasureSpec, spec);
}
}
}
int startSpace = 0, endSpace = 0;
if (isStartLine) {
startSpace = computeStartSpace(helper, layoutInVertical, !helper.getReverseLayout(), isOverLapMargin);
}
if (isEndLine) {
endSpace = computeEndSpace(helper, layoutInVertical, !helper.getReverseLayout(), isOverLapMargin);
}
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
layoutChildWithMargin(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 com.alibaba.android.vlayout.OrientationHelperEx in project vlayout by alibaba.
the class OnePlusNLayoutHelper method handleHeader.
private int handleHeader(View header, LayoutStateWrapper layoutState, LayoutChunkResult result, LayoutManagerHelper helper, boolean layoutInVertical, int parentWidth, int parentHeight, int parentHPadding, int parentVPadding) {
if (header == null) {
return 0;
}
OrientationHelperEx orientationHelper = helper.getMainOrientationHelper();
final VirtualLayoutManager.LayoutParams lp = (LayoutParams) header.getLayoutParams();
// fill width
int widthSpec = helper.getChildMeasureSpec(parentWidth - parentHPadding, layoutInVertical ? MATCH_PARENT : lp.width, !layoutInVertical);
int heightSpec = helper.getChildMeasureSpec(parentHeight - parentVPadding, layoutInVertical ? lp.height : MeasureSpec.EXACTLY, layoutInVertical);
helper.measureChildWithMargins(header, widthSpec, heightSpec);
return orientationHelper.getDecoratedMeasurement(header);
}
Aggregations