List of usage examples for android.view View measure
public final void measure(int widthMeasureSpec, int heightMeasureSpec)
This is called to find out how big a view should be.
From source file:com.actionbarsherlock.internal.widget.ActionBarView.java
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int childCount = getChildCount(); if (mIsCollapsable) { int visibleChildren = 0; for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE && !(child == mMenuView && mMenuView.getChildCount() == 0)) { visibleChildren++;/* ww w . ja va 2s .co m*/ } } if (visibleChildren == 0) { // No size for an empty action bar when collapsable. setMeasuredDimension(0, 0); mIsCollapsed = true; return; } } mIsCollapsed = false; int widthMode = MeasureSpec.getMode(widthMeasureSpec); if (widthMode != MeasureSpec.EXACTLY) { throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + "with android:layout_width=\"match_parent\" (or fill_parent)"); } int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (heightMode != MeasureSpec.AT_MOST) { throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + "with android:layout_height=\"wrap_content\""); } int contentWidth = MeasureSpec.getSize(widthMeasureSpec); int maxHeight = mContentHeight > 0 ? mContentHeight : MeasureSpec.getSize(heightMeasureSpec); final int verticalPadding = getPaddingTop() + getPaddingBottom(); final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int height = maxHeight - verticalPadding; final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); int availableWidth = contentWidth - paddingLeft - paddingRight; int leftOfCenter = availableWidth / 2; int rightOfCenter = leftOfCenter; HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout; if (homeLayout.getVisibility() != GONE) { final ViewGroup.LayoutParams lp = homeLayout.getLayoutParams(); int homeWidthSpec; if (lp.width < 0) { homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST); } else { homeWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); } homeLayout.measure(homeWidthSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); final int homeWidth = homeLayout.getMeasuredWidth() + homeLayout.getLeftOffset(); availableWidth = Math.max(0, availableWidth - homeWidth); leftOfCenter = Math.max(0, availableWidth - homeWidth); } if (mMenuView != null && mMenuView.getParent() == this) { availableWidth = measureChildView(mMenuView, availableWidth, childSpecHeight, 0); rightOfCenter = Math.max(0, rightOfCenter - mMenuView.getMeasuredWidth()); } if (mIndeterminateProgressView != null && mIndeterminateProgressView.getVisibility() != GONE) { availableWidth = measureChildView(mIndeterminateProgressView, availableWidth, childSpecHeight, 0); rightOfCenter = Math.max(0, rightOfCenter - mIndeterminateProgressView.getMeasuredWidth()); } final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE && (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0; if (mExpandedActionView == null) { switch (mNavigationMode) { case ActionBar.NAVIGATION_MODE_LIST: if (mListNavLayout != null) { final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding; availableWidth = Math.max(0, availableWidth - itemPaddingSize); leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize); mListNavLayout.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); final int listNavWidth = mListNavLayout.getMeasuredWidth(); availableWidth = Math.max(0, availableWidth - listNavWidth); leftOfCenter = Math.max(0, leftOfCenter - listNavWidth); } break; case ActionBar.NAVIGATION_MODE_TABS: if (mTabScrollView != null) { final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding; availableWidth = Math.max(0, availableWidth - itemPaddingSize); leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize); mTabScrollView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); final int tabWidth = mTabScrollView.getMeasuredWidth(); availableWidth = Math.max(0, availableWidth - tabWidth); leftOfCenter = Math.max(0, leftOfCenter - tabWidth); } break; } } View customView = null; if (mExpandedActionView != null) { customView = mExpandedActionView; } else if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) { customView = mCustomNavView; } if (customView != null) { final ViewGroup.LayoutParams lp = generateLayoutParams(customView.getLayoutParams()); final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ? (ActionBar.LayoutParams) lp : null; int horizontalMargin = 0; int verticalMargin = 0; if (ablp != null) { horizontalMargin = ablp.leftMargin + ablp.rightMargin; verticalMargin = ablp.topMargin + ablp.bottomMargin; } // If the action bar is wrapping to its content height, don't allow a custom // view to MATCH_PARENT. int customNavHeightMode; if (mContentHeight <= 0) { customNavHeightMode = MeasureSpec.AT_MOST; } else { customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ? MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; } final int customNavHeight = Math.max(0, (lp.height >= 0 ? Math.min(lp.height, height) : height) - verticalMargin); final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ? MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; int customNavWidth = Math.max(0, (lp.width >= 0 ? Math.min(lp.width, availableWidth) : availableWidth) - horizontalMargin); final int hgrav = (ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY) & Gravity.HORIZONTAL_GRAVITY_MASK; // Centering a custom view is treated specially; we try to center within the whole // action bar rather than in the available space. if (hgrav == Gravity.CENTER_HORIZONTAL && lp.width == LayoutParams.MATCH_PARENT) { customNavWidth = Math.min(leftOfCenter, rightOfCenter) * 2; } customView.measure(MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode), MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode)); availableWidth -= horizontalMargin + customView.getMeasuredWidth(); } if (mExpandedActionView == null && showTitle) { availableWidth = measureChildView(mTitleLayout, availableWidth, MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY), 0); leftOfCenter = Math.max(0, leftOfCenter - mTitleLayout.getMeasuredWidth()); } if (mContentHeight <= 0) { int measuredHeight = 0; for (int i = 0; i < childCount; i++) { View v = getChildAt(i); int paddedViewHeight = v.getMeasuredHeight() + verticalPadding; if (paddedViewHeight > measuredHeight) { measuredHeight = paddedViewHeight; } } setMeasuredDimension(contentWidth, measuredHeight); } else { setMeasuredDimension(contentWidth, maxHeight); } if (mContextView != null) { mContextView.setContentHeight(getMeasuredHeight()); } if (mProgressView != null && mProgressView.getVisibility() != GONE) { mProgressView.measure( MeasureSpec.makeMeasureSpec(contentWidth - mProgressBarPadding * 2, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST)); } }
From source file:com.devabit.takestock.ui.widget.FlexboxLayout.java
/** * Sub method for {@link #onMeasure(int, int)}, when the main axis direction is horizontal * (either left to right or right to left). * * @param widthMeasureSpec horizontal space requirements as imposed by the parent * @param heightMeasureSpec vertical space requirements as imposed by the parent * @see #onMeasure(int, int)/*from ww w. j ava 2 s . c o m*/ * @see #setFlexDirection(int) * @see #setFlexWrap(int) * @see #setAlignItems(int) * @see #setAlignContent(int) */ private void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int childState = 0; mFlexLines.clear(); // Determine how many flex lines are needed in this layout by measuring each child. // (Expand or shrink the view depending on the flexGrow and flexShrink attributes in a later // loop) { int childCount = getChildCount(); int paddingStart = ViewCompat.getPaddingStart(this); int paddingEnd = ViewCompat.getPaddingEnd(this); int largestHeightInRow = Integer.MIN_VALUE; FlexLine flexLine = new FlexLine(); flexLine.mainSize = paddingStart + paddingEnd; for (int i = 0; i < childCount; i++) { View child = getReorderedChildAt(i); if (child == null) { addFlexLineIfLastFlexItem(i, childCount, flexLine); continue; } else if (child.getVisibility() == View.GONE) { flexLine.itemCount++; addFlexLineIfLastFlexItem(i, childCount, flexLine); continue; } FlexboxLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (lp.alignSelf == LayoutParams.ALIGN_SELF_STRETCH) { flexLine.indicesAlignSelfStretch.add(i); } int childWidth = lp.width; if (lp.flexBasisPercent != LayoutParams.FLEX_BASIS_PERCENT_DEFAULT && widthMode == MeasureSpec.EXACTLY) { childWidth = Math.round(widthSize * lp.flexBasisPercent); // Use the dimension from the layout_width attribute if the widthMode is not // MeasureSpec.EXACTLY even if any fraction value is set to // layout_flexBasisPercent. // There are likely quite few use cases where assigning any fraction values // with widthMode is not MeasureSpec.EXACTLY (e.g. FlexboxLayout's layout_width // is set to wrap_content) } int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin, childWidth); int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); // Check the size constraint after the first measurement for the child // To prevent the child's width/height violate the size constraints imposed by the // {@link LayoutParams#minWidth}, {@link LayoutParams#minHeight}, // {@link LayoutParams#maxWidth} and {@link LayoutParams#maxHeight} attributes. // E.g. When the child's layout_width is wrap_content the measured width may be // less than the min width after the first measurement. checkSizeConstraints(child); childState = ViewCompat.combineMeasuredStates(childState, ViewCompat.getMeasuredState(child)); largestHeightInRow = Math.max(largestHeightInRow, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); if (isWrapRequired(mFlexWrap, widthMode, widthSize, flexLine.mainSize, child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin, lp)) { if (flexLine.itemCount > 0) { mFlexLines.add(flexLine); } flexLine = new FlexLine(); flexLine.itemCount = 1; flexLine.mainSize = paddingStart + paddingEnd; largestHeightInRow = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; } else { flexLine.itemCount++; } flexLine.mainSize += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; flexLine.totalFlexGrow += lp.flexGrow; flexLine.totalFlexShrink += lp.flexShrink; // Temporarily set the cross axis length as the largest child in the row // Expand along the cross axis depending on the mAlignContent property if needed // later flexLine.crossSize = Math.max(flexLine.crossSize, largestHeightInRow); if (mFlexWrap != FLEX_WRAP_WRAP_REVERSE) { flexLine.maxBaseline = Math.max(flexLine.maxBaseline, child.getBaseline() + lp.topMargin); } else { // if the flex wrap property is FLEX_WRAP_WRAP_REVERSE, calculate the // baseline as the distance from the cross end and the baseline // since the cross size calculation is based on the distance from the cross end flexLine.maxBaseline = Math.max(flexLine.maxBaseline, child.getMeasuredHeight() - child.getBaseline() + lp.bottomMargin); } addFlexLineIfLastFlexItem(i, childCount, flexLine); } } determineMainSize(mFlexDirection, widthMeasureSpec, heightMeasureSpec); // TODO: Consider the case any individual child's alignSelf is set to ALIGN_SELF_BASELINE if (mAlignItems == ALIGN_ITEMS_BASELINE) { int viewIndex = 0; for (FlexLine flexLine : mFlexLines) { // The largest height value that also take the baseline shift into account int largestHeightInLine = Integer.MIN_VALUE; for (int i = viewIndex; i < viewIndex + flexLine.itemCount; i++) { View child = getReorderedChildAt(i); LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (mFlexWrap != FLEX_WRAP_WRAP_REVERSE) { int marginTop = flexLine.maxBaseline - child.getBaseline(); marginTop = Math.max(marginTop, lp.topMargin); largestHeightInLine = Math.max(largestHeightInLine, child.getHeight() + marginTop + lp.bottomMargin); } else { int marginBottom = flexLine.maxBaseline - child.getMeasuredHeight() + child.getBaseline(); marginBottom = Math.max(marginBottom, lp.bottomMargin); largestHeightInLine = Math.max(largestHeightInLine, child.getHeight() + lp.topMargin + marginBottom); } } flexLine.crossSize = largestHeightInLine; viewIndex += flexLine.itemCount; } } determineCrossSize(mFlexDirection, widthMeasureSpec, heightMeasureSpec, getPaddingTop() + getPaddingBottom()); // Now cross size for each flex line is determined. // Expand the views if alignItems (or alignSelf in each child view) is set to stretch stretchViews(mFlexDirection, mAlignItems); setMeasuredDimensionForFlex(mFlexDirection, widthMeasureSpec, heightMeasureSpec, childState); }
From source file:android.support.v17.leanback.widget.GridLayoutManager.java
private void measureScrapChild(int position, int widthSpec, int heightSpec, int[] measuredDimension) { View view = mRecycler.getViewForPosition(position); if (view != null) { final LayoutParams p = (LayoutParams) view.getLayoutParams(); calculateItemDecorationsForChild(view, sTempRect); int widthUsed = p.leftMargin + p.rightMargin + sTempRect.left + sTempRect.right; int heightUsed = p.topMargin + p.bottomMargin + sTempRect.top + sTempRect.bottom; int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight() + widthUsed, p.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom() + heightUsed, p.height); view.measure(childWidthSpec, childHeightSpec); measuredDimension[0] = getDecoratedMeasuredWidthWithMargin(view); measuredDimension[1] = getDecoratedMeasuredHeightWithMargin(view); mRecycler.recycleView(view);/*from ww w.j ava 2 s . c o m*/ } }
From source file:com.google.android.flexbox.FlexboxLayoutManager.java
private int layoutFlexLineMainAxisHorizontal(FlexLine flexLine, LayoutState layoutState) { assert mFlexboxHelper.mMeasureSpecCache != null; int paddingLeft = getPaddingLeft(); int paddingRight = getPaddingRight(); int parentWidth = getWidth(); int childTop = layoutState.mOffset; if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { childTop = childTop - flexLine.mCrossSize; }/*w w w . ja v a 2 s .co m*/ int startPosition = layoutState.mPosition; float childLeft; // Only used when mIsRtl is true float childRight; float spaceBetweenItem = 0f; switch (mJustifyContent) { case JustifyContent.FLEX_START: childLeft = paddingLeft; childRight = parentWidth - paddingRight; break; case JustifyContent.FLEX_END: childLeft = parentWidth - flexLine.mMainSize + paddingRight; childRight = flexLine.mMainSize - paddingLeft; break; case JustifyContent.CENTER: childLeft = paddingLeft + (parentWidth - flexLine.mMainSize) / 2f; childRight = parentWidth - paddingRight - (parentWidth - flexLine.mMainSize) / 2f; break; case JustifyContent.SPACE_AROUND: if (flexLine.mItemCount != 0) { spaceBetweenItem = (parentWidth - flexLine.mMainSize) / (float) flexLine.mItemCount; } childLeft = paddingLeft + spaceBetweenItem / 2f; childRight = parentWidth - paddingRight - spaceBetweenItem / 2f; break; case JustifyContent.SPACE_BETWEEN: childLeft = paddingLeft; float denominator = flexLine.mItemCount != 1 ? flexLine.mItemCount - 1 : 1f; spaceBetweenItem = (parentWidth - flexLine.mMainSize) / denominator; childRight = parentWidth - paddingRight; break; case JustifyContent.SPACE_EVENLY: if (flexLine.mItemCount != 0) { spaceBetweenItem = (parentWidth - flexLine.mMainSize) / (float) (flexLine.mItemCount + 1); } childLeft = paddingLeft + spaceBetweenItem; childRight = parentWidth - paddingRight - spaceBetweenItem; break; default: throw new IllegalStateException("Invalid justifyContent is set: " + mJustifyContent); } childLeft -= mAnchorInfo.mPerpendicularCoordinate; childRight -= mAnchorInfo.mPerpendicularCoordinate; spaceBetweenItem = Math.max(spaceBetweenItem, 0); // Used only when mLayoutDirection == LayoutState.LAYOUT_START to remember the index // a flex item should be inserted int indexInFlexLine = 0; for (int i = startPosition, itemCount = flexLine.getItemCount(); i < startPosition + itemCount; i++) { View view = getFlexItemAt(i); if (view == null) { continue; } if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { calculateItemDecorationsForChild(view, TEMP_RECT); addView(view); } else { calculateItemDecorationsForChild(view, TEMP_RECT); addView(view, indexInFlexLine); indexInFlexLine++; } // Retrieve the measure spec from the cache because the view may be re-created when // retrieved from Recycler, in that case measured width/height are set to 0 even // each visible child should be measured at least once in the FlexboxHelper long measureSpec = mFlexboxHelper.mMeasureSpecCache[i]; int widthSpec = mFlexboxHelper.extractLowerInt(measureSpec); int heightSpec = mFlexboxHelper.extractHigherInt(measureSpec); LayoutParams lp = (LayoutParams) view.getLayoutParams(); if (shouldMeasureChild(view, widthSpec, heightSpec, lp)) { view.measure(widthSpec, heightSpec); } childLeft += (lp.leftMargin + getLeftDecorationWidth(view)); childRight -= (lp.rightMargin + getRightDecorationWidth(view)); int topWithDecoration = childTop + getTopDecorationHeight(view); if (mIsRtl) { mFlexboxHelper.layoutSingleChildHorizontal(view, flexLine, Math.round(childRight) - view.getMeasuredWidth(), topWithDecoration, Math.round(childRight), topWithDecoration + view.getMeasuredHeight()); } else { mFlexboxHelper.layoutSingleChildHorizontal(view, flexLine, Math.round(childLeft), topWithDecoration, Math.round(childLeft) + view.getMeasuredWidth(), topWithDecoration + view.getMeasuredHeight()); } childLeft += (view.getMeasuredWidth() + lp.rightMargin + getRightDecorationWidth(view) + spaceBetweenItem); childRight -= (view.getMeasuredWidth() + lp.leftMargin + getLeftDecorationWidth(view) + spaceBetweenItem); } layoutState.mFlexLinePosition += mLayoutState.mLayoutDirection; return flexLine.getCrossSize(); }
From source file:com.devabit.takestock.ui.widget.FlexboxLayout.java
/** * Shrink the flex items along the main axis based on the individual flexShrink attribute. * * @param flexLine the flex line to which flex items belong * @param flexDirection the flexDirection value for this FlexboxLayout * @param maxMainSize the maximum main size. Shrank main size will be this size * @param paddingAlongMainAxis the padding value along the main axis * @param startIndex the start index of the children views to be shrank. This index * needs to/*from w w w. ja va2 s .co m*/ * be an absolute index in the flex container (FlexboxLayout), * not the relative index in the flex line. * @return the next index, the next flex line's first flex item starts from the returned index * @see #getFlexDirection() * @see #setFlexDirection(int) * @see LayoutParams#flexShrink */ private int shrinkFlexItems(FlexLine flexLine, @FlexDirection int flexDirection, int maxMainSize, int paddingAlongMainAxis, int startIndex) { int childIndex = startIndex; int sizeBeforeShrink = flexLine.mainSize; if (flexLine.totalFlexShrink <= 0 || maxMainSize > flexLine.mainSize) { childIndex += flexLine.itemCount; return childIndex; } boolean needsReshrink = false; float unitShrink = (flexLine.mainSize - maxMainSize) / flexLine.totalFlexShrink; float accumulatedRoundError = 0; flexLine.mainSize = paddingAlongMainAxis; for (int i = 0; i < flexLine.itemCount; i++) { View child = getReorderedChildAt(childIndex); if (child == null) { continue; } else if (child.getVisibility() == View.GONE) { childIndex++; continue; } LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (flexDirection == FLEX_DIRECTION_ROW || flexDirection == FLEX_DIRECTION_ROW_REVERSE) { // The direction of main axis is horizontal if (!mChildrenFrozen[childIndex]) { float rawCalculatedWidth = child.getMeasuredWidth() - unitShrink * lp.flexShrink; if (i == flexLine.itemCount - 1) { rawCalculatedWidth += accumulatedRoundError; accumulatedRoundError = 0; } int newWidth = Math.round(rawCalculatedWidth); if (newWidth < lp.minWidth) { // This means the child doesn't have enough space to distribute the negative // free space. To adjust the flex line length down to the maxMainSize, remaining // negative free space needs to be re-distributed to other flex items // (children views). In that case, invoke this method again with the same // startIndex. needsReshrink = true; newWidth = lp.minWidth; mChildrenFrozen[childIndex] = true; flexLine.totalFlexShrink -= lp.flexShrink; } else { accumulatedRoundError += (rawCalculatedWidth - newWidth); if (accumulatedRoundError > 1.0) { newWidth += 1; accumulatedRoundError -= 1; } else if (accumulatedRoundError < -1.0) { newWidth -= 1; accumulatedRoundError += 1; } } child.measure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY)); } flexLine.mainSize += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } else { // The direction of main axis is vertical if (!mChildrenFrozen[childIndex]) { float rawCalculatedHeight = child.getMeasuredHeight() - unitShrink * lp.flexShrink; if (i == flexLine.itemCount - 1) { rawCalculatedHeight += accumulatedRoundError; accumulatedRoundError = 0; } int newHeight = Math.round(rawCalculatedHeight); if (newHeight < lp.minHeight) { // Need to invoke this method again like the case flex direction is vertical needsReshrink = true; newHeight = lp.minHeight; mChildrenFrozen[childIndex] = true; flexLine.totalFlexShrink -= lp.flexShrink; } else { accumulatedRoundError += (rawCalculatedHeight - newHeight); if (accumulatedRoundError > 1.0) { newHeight += 1; accumulatedRoundError -= 1; } else if (accumulatedRoundError < -1.0) { newHeight -= 1; accumulatedRoundError += 1; } } child.measure(MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY)); } flexLine.mainSize += child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; } childIndex++; } if (needsReshrink && sizeBeforeShrink != flexLine.mainSize) { // Re-invoke the method with the same startIndex to distribute the negative free space // that wasn't fully distributed (because some views length were not enough) shrinkFlexItems(flexLine, flexDirection, maxMainSize, paddingAlongMainAxis, startIndex); } return childIndex; }
From source file:com.devabit.takestock.ui.widget.FlexboxLayout.java
/** * Expand the flex items along the main axis based on the individual flexGrow attribute. * * @param flexLine the flex line to which flex items belong * @param flexDirection the flexDirection value for this FlexboxLayout * @param maxMainSize the maximum main size. Expanded main size will be this size * @param paddingAlongMainAxis the padding value along the main axis * @param startIndex the start index of the children views to be expanded. This index * needs to// w ww . j ava 2 s.co m * be an absolute index in the flex container (FlexboxLayout), * not the relative index in the flex line. * @return the next index, the next flex line's first flex item starts from the returned index * @see #getFlexDirection() * @see #setFlexDirection(int) * @see LayoutParams#flexGrow */ private int expandFlexItems(FlexLine flexLine, @FlexDirection int flexDirection, int maxMainSize, int paddingAlongMainAxis, int startIndex) { int childIndex = startIndex; if (flexLine.totalFlexGrow <= 0 || maxMainSize < flexLine.mainSize) { childIndex += flexLine.itemCount; return childIndex; } int sizeBeforeExpand = flexLine.mainSize; boolean needsReexpand = false; float unitSpace = (maxMainSize - flexLine.mainSize) / flexLine.totalFlexGrow; flexLine.mainSize = paddingAlongMainAxis; float accumulatedRoundError = 0; for (int i = 0; i < flexLine.itemCount; i++) { View child = getReorderedChildAt(childIndex); if (child == null) { continue; } else if (child.getVisibility() == View.GONE) { childIndex++; continue; } LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (flexDirection == FLEX_DIRECTION_ROW || flexDirection == FLEX_DIRECTION_ROW_REVERSE) { // The direction of the main axis is horizontal if (!mChildrenFrozen[childIndex]) { float rawCalculatedWidth = child.getMeasuredWidth() + unitSpace * lp.flexGrow; if (i == flexLine.itemCount - 1) { rawCalculatedWidth += accumulatedRoundError; accumulatedRoundError = 0; } int newWidth = Math.round(rawCalculatedWidth); if (newWidth > lp.maxWidth) { // This means the child can't expand beyond the value of the maxWidth attribute. // To adjust the flex line length to the size of maxMainSize, remaining // positive free space needs to be re-distributed to other flex items // (children views). In that case, invoke this method again with the same // startIndex. needsReexpand = true; newWidth = lp.maxWidth; mChildrenFrozen[childIndex] = true; flexLine.totalFlexGrow -= lp.flexGrow; } else { accumulatedRoundError += (rawCalculatedWidth - newWidth); if (accumulatedRoundError > 1.0) { newWidth += 1; accumulatedRoundError -= 1.0; } else if (accumulatedRoundError < -1.0) { newWidth -= 1; accumulatedRoundError += 1.0; } } child.measure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY)); } flexLine.mainSize += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } else { // The direction of the main axis is vertical if (!mChildrenFrozen[childIndex]) { float rawCalculatedHeight = child.getMeasuredHeight() + unitSpace * lp.flexGrow; if (i == flexLine.itemCount - 1) { rawCalculatedHeight += accumulatedRoundError; accumulatedRoundError = 0; } int newHeight = Math.round(rawCalculatedHeight); if (newHeight > lp.maxHeight) { // This means the child can't expand beyond the value of the maxHeight // attribute. // To adjust the flex line length to the size of maxMainSize, remaining // positive free space needs to be re-distributed to other flex items // (children views). In that case, invoke this method again with the same // startIndex. needsReexpand = true; newHeight = lp.maxHeight; mChildrenFrozen[childIndex] = true; flexLine.totalFlexGrow -= lp.flexGrow; } else { accumulatedRoundError += (rawCalculatedHeight - newHeight); if (accumulatedRoundError > 1.0) { newHeight += 1; accumulatedRoundError -= 1.0; } else if (accumulatedRoundError < -1.0) { newHeight -= 1; accumulatedRoundError += 1.0; } } child.measure(MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY)); } flexLine.mainSize += child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; } childIndex++; } if (needsReexpand && sizeBeforeExpand != flexLine.mainSize) { // Re-invoke the method with the same startIndex to distribute the positive free space // that wasn't fully distributed (because of maximum length constraint) expandFlexItems(flexLine, flexDirection, maxMainSize, paddingAlongMainAxis, startIndex); } return childIndex; }
From source file:android.support.v7.widget.AbstractXpListPopupWindow.java
/** * <p>Builds the popup window's content and returns the height the popup * should have. Returns -1 when the content already exists.</p> * * @return the content's height or -1 if content already exists *//*from ww w.j av a 2 s. com*/ private int buildDropDown() { ViewGroup dropDownView; int otherHeights = 0; if (mDropDownList == null) { Context context = mContext; /** * This Runnable exists for the sole purpose of checking if the view layout has got * completed and if so call showDropDown to display the drop down. This is used to show * the drop down as soon as possible after user opens up the search dialog, without * waiting for the normal UI pipeline to do it's job which is slower than this method. */ mShowDropDownRunnable = new Runnable() { public void run() { // View layout should be all done before displaying the drop down. View view = getAnchorView(); if (view != null && view.getWindowToken() != null) { show(); } } }; mDropDownList = createDropDownListView(context, !mModal); if (mDropDownListHighlight != null) { mDropDownList.setSelector(mDropDownListHighlight); } mDropDownList.setAdapter(mAdapter); mDropDownList.setOnItemClickListener(mItemClickListener); mDropDownList.setFocusable(true); mDropDownList.setFocusableInTouchMode(true); mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if (position != -1) { XpDropDownListView dropDownList = mDropDownList; if (dropDownList != null) { dropDownList.setListSelectionHidden(false); } } } public void onNothingSelected(AdapterView<?> parent) { } }); mDropDownList.setOnScrollListener(mScrollListener); if (mItemSelectedListener != null) { mDropDownList.setOnItemSelectedListener(mItemSelectedListener); } dropDownView = mDropDownList; View hintView = mPromptView; if (hintView != null) { // if a hint has been specified, we accomodate more space for it and // add a text view in the drop down menu, at the bottom of the list LinearLayout hintContainer = new LinearLayout(context); hintContainer.setOrientation(LinearLayout.VERTICAL); LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f); switch (mPromptPosition) { case POSITION_PROMPT_BELOW: hintContainer.addView(dropDownView, hintParams); hintContainer.addView(hintView); break; case POSITION_PROMPT_ABOVE: hintContainer.addView(hintView); hintContainer.addView(dropDownView, hintParams); break; default: Log.e(TAG, "Invalid hint position " + mPromptPosition); break; } // Measure the hint's height to find how much more vertical // space we need to add to the drop down's height. final int widthSize; final int widthMode; if (mDropDownWidth >= 0) { widthMode = MeasureSpec.AT_MOST; widthSize = mDropDownWidth > mDropDownMaxWidth ? mDropDownMaxWidth : mDropDownWidth; // widthSize = mDropDownWidth; } else { if (mDropDownMaxWidth >= 0) { widthMode = MeasureSpec.AT_MOST; widthSize = mDropDownMaxWidth; } else { widthMode = MeasureSpec.UNSPECIFIED; widthSize = 0; } } //noinspection Range final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); final int heightSpec = MeasureSpec.UNSPECIFIED; hintView.measure(widthSpec, heightSpec); hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams(); otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin + hintParams.bottomMargin; dropDownView = hintContainer; } mPopup.setContentView(dropDownView); } else { dropDownView = (ViewGroup) mPopup.getContentView(); final View view = mPromptView; if (view != null) { LinearLayout.LayoutParams hintParams = (LinearLayout.LayoutParams) view.getLayoutParams(); otherHeights = view.getMeasuredHeight() + hintParams.topMargin + hintParams.bottomMargin; } } // getMaxAvailableHeight() subtracts the padding, so we put it back // to get the available height for the whole window int padding = 0; Drawable background = mPopup.getBackground(); if (background != null) { background.getPadding(mTempRect); padding = mTempRect.top + mTempRect.bottom; // If we don't have an explicit vertical offset, determine one from the window // background so that content will line up. // if (!mDropDownVerticalOffsetSet) { // mDropDownVerticalOffset = -mTempRect.top; // } } else { mTempRect.setEmpty(); } final int verticalMargin = mMargins.top + mMargins.bottom; // Max height available on the screen for a popup. final boolean ignoreBottomDecorations = mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED; // final int maxHeight = getMaxAvailableHeight(getAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations); final int maxHeight = getMaxAvailableHeight(getAnchorView(), ignoreBottomDecorations); if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) { return maxHeight - verticalMargin + padding; } final int childWidthSpec; switch (mDropDownWidth) { case ViewGroup.LayoutParams.WRAP_CONTENT: childWidthSpec = MeasureSpec.makeMeasureSpec(getAnchorView().getWidth() - (mMargins.left + mMargins.right) - (mTempRect.left + mTempRect.right), MeasureSpec.AT_MOST); break; case ViewGroup.LayoutParams.MATCH_PARENT: childWidthSpec = MeasureSpec.makeMeasureSpec(mContext.getResources().getDisplayMetrics().widthPixels - (mMargins.left + mMargins.right) - (mTempRect.left + mTempRect.right), MeasureSpec.EXACTLY); break; case PREFERRED: int widthSize; int widthMode; if (mDropDownMaxWidth >= 0) { widthSize = mDropDownMaxWidth - (mMargins.left + mMargins.right) - (mTempRect.left + mTempRect.right); widthMode = MeasureSpec.AT_MOST; childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); } else { widthMode = MeasureSpec.AT_MOST; if (mDropDownMaxWidth == WRAP_CONTENT) { widthSize = getAnchorView().getWidth() - (mMargins.left + mMargins.right) - (mTempRect.left + mTempRect.right); } else { // MATCH_PARENT widthSize = mContext.getResources().getDisplayMetrics().widthPixels - (mMargins.left + mMargins.right) - (mTempRect.left + mTempRect.right); } childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); } break; default: //noinspection Range childWidthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.EXACTLY); break; } final int listPadding = mDropDownList.getPaddingTop() + mDropDownList.getPaddingBottom(); final int listContent = mDropDownList.measureHeightOfChildrenCompat(childWidthSpec, 0, XpDropDownListView.NO_POSITION, maxHeight - otherHeights - verticalMargin - listPadding + padding, -1); // add padding only if the list has items in it, that way we don't show // the popup if it is not needed if (otherHeights > 0 || listContent > 0) otherHeights += padding + listPadding; return listContent + otherHeights; }
From source file:com.example.uidemo.widget.waterfall.StaggeredGridView.java
/** * Measure and layout all currently visible children. * * @param queryAdapter true to requery the adapter for view data */// ww w . ja va 2s . c om final void layoutChildren(boolean queryAdapter) { final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int itemMargin = mItemMargin; final int colWidth = (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount; mColWidth = colWidth; int rebuildLayoutRecordsBefore = -1; int rebuildLayoutRecordsAfter = -1; Arrays.fill(mItemBottoms, Integer.MIN_VALUE); final int childCount = getChildCount(); int amountRemoved = 0; for (int i = 0; i < childCount; i++) { View child = getChildAt(i); LayoutParams lp = (LayoutParams) child.getLayoutParams(); final int col = lp.column; final int position = mFirstPosition + i; final boolean needsLayout = queryAdapter || child.isLayoutRequested(); if (queryAdapter) { View newView = obtainView(position, child); if (newView == null) { // child has been removed removeViewAt(i); if (i - 1 >= 0) invalidateLayoutRecordsAfterPosition(i - 1); amountRemoved++; continue; } else if (newView != child) { removeViewAt(i); addView(newView, i); child = newView; } lp = (LayoutParams) child.getLayoutParams(); // Might have changed } final int span = Math.min(mColCount, lp.span); final int widthSize = colWidth * span + itemMargin * (span - 1); if (needsLayout) { final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); final int heightSpec; if (lp.height == LayoutParams.WRAP_CONTENT) { heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } else { heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); } child.measure(widthSpec, heightSpec); } int childTop = mItemBottoms[col] > Integer.MIN_VALUE ? mItemBottoms[col] + mItemMargin : child.getTop(); if (span > 1) { int lowest = childTop; for (int j = col + 1; j < col + span; j++) { final int bottom = mItemBottoms[j] + mItemMargin; if (bottom > lowest) { lowest = bottom; } } childTop = lowest; } final int childHeight = child.getMeasuredHeight(); final int childBottom = childTop + childHeight; final int childLeft = paddingLeft + col * (colWidth + itemMargin); final int childRight = childLeft + child.getMeasuredWidth(); child.layout(childLeft, childTop, childRight, childBottom); for (int j = col; j < col + span; j++) { mItemBottoms[j] = childBottom; } final LayoutRecord rec = mLayoutRecords.get(position); if (rec != null && rec.height != childHeight) { // Invalidate our layout records for everything before this. rec.height = childHeight; rebuildLayoutRecordsBefore = position; } if (rec != null && rec.span != span) { // Invalidate our layout records for everything after this. rec.span = span; rebuildLayoutRecordsAfter = position; } } // Update mItemBottoms for any empty columns for (int i = 0; i < mColCount; i++) { if (mItemBottoms[i] == Integer.MIN_VALUE) { mItemBottoms[i] = mItemTops[i]; } } if (rebuildLayoutRecordsBefore >= 0 || rebuildLayoutRecordsAfter >= 0) { if (rebuildLayoutRecordsBefore >= 0) { invalidateLayoutRecordsBeforePosition(rebuildLayoutRecordsBefore); } if (rebuildLayoutRecordsAfter >= 0) { invalidateLayoutRecordsAfterPosition(rebuildLayoutRecordsAfter); } for (int i = 0; i < (childCount - amountRemoved); i++) { final int position = mFirstPosition + i; final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); LayoutRecord rec = mLayoutRecords.get(position); if (rec == null) { rec = new LayoutRecord(); mLayoutRecords.put(position, rec); } rec.column = lp.column; rec.height = child.getHeight(); rec.id = lp.id; rec.span = Math.min(mColCount, lp.span); } } if (this.mSelectorPosition != INVALID_POSITION) { View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) positionSelector(mMotionPosition, child); } else if (mTouchMode > TOUCH_MODE_DOWN) { View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) positionSelector(mMotionPosition, child); } else { mSelectorRect.setEmpty(); } }
From source file:cn.iterlog.myapplication.widget.overscroll.StaggeredGridView.java
/** * Measure and layout all currently visible children. * * @param queryAdapter true to requery the adapter for view data *//*from w ww . j a v a 2 s .c om*/ final void layoutChildren(boolean queryAdapter) { final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int itemMargin = mItemMargin; final int colWidth = (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)) / mColCount; mColWidth = colWidth; int rebuildLayoutRecordsBefore = -1; int rebuildLayoutRecordsAfter = -1; Arrays.fill(mItemBottoms, Integer.MIN_VALUE); final int childCount = getChildCount(); int amountRemoved = 0; for (int i = 0; i < childCount; i++) { View child = getChildAt(i); LayoutParams lp = (LayoutParams) child.getLayoutParams(); final int col = lp.column; final int position = mFirstPosition + i; final boolean needsLayout = queryAdapter || child.isLayoutRequested(); if (queryAdapter) { View newView = obtainView(position, child); if (newView == null) { // child has been removed removeViewAt(i); if (i - 1 >= 0) invalidateLayoutRecordsAfterPosition(i - 1); amountRemoved++; continue; } else if (newView != child) { removeViewAt(i); addView(newView, i); child = newView; } lp = (LayoutParams) child.getLayoutParams(); // Might have changed } final int span = Math.min(mColCount, lp.span); final int widthSize = colWidth * span + itemMargin * (span - 1); if (needsLayout) { final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); final int heightSpec; if (lp.height == LayoutParams.WRAP_CONTENT) { heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } else { heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); } child.measure(widthSpec, heightSpec); } int childTop = mItemBottoms[col] > Integer.MIN_VALUE ? mItemBottoms[col] + mItemMargin : child.getTop(); if (span > 1) { int lowest = childTop; for (int j = col + 1; j < col + span; j++) { final int bottom = mItemBottoms[j] + mItemMargin; if (bottom > lowest) { lowest = bottom; } } childTop = lowest; } final int childHeight = child.getMeasuredHeight(); final int childBottom = childTop + childHeight; final int childLeft = paddingLeft + col * (colWidth + itemMargin); final int childRight = childLeft + child.getMeasuredWidth(); child.layout(childLeft, childTop, childRight, childBottom); for (int j = col; j < col + span; j++) { mItemBottoms[j] = childBottom; } final LayoutRecord rec = mLayoutRecords.get(position); if (rec != null && rec.height != childHeight) { // Invalidate our layout records for everything before this. rec.height = childHeight; rebuildLayoutRecordsBefore = position; } if (rec != null && rec.span != span) { // Invalidate our layout records for everything after this. rec.span = span; rebuildLayoutRecordsAfter = position; } } // Update mItemBottoms for any empty columns for (int i = 0; i < mColCount; i++) { if (mItemBottoms[i] == Integer.MIN_VALUE) { mItemBottoms[i] = mItemTops[i]; } } if (rebuildLayoutRecordsBefore >= 0 || rebuildLayoutRecordsAfter >= 0) { if (rebuildLayoutRecordsBefore >= 0) { invalidateLayoutRecordsBeforePosition(rebuildLayoutRecordsBefore); } if (rebuildLayoutRecordsAfter >= 0) { invalidateLayoutRecordsAfterPosition(rebuildLayoutRecordsAfter); } for (int i = 0; i < (childCount - amountRemoved); i++) { final int position = mFirstPosition + i; final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); LayoutRecord rec = mLayoutRecords.get(position); if (rec == null) { rec = new LayoutRecord(); mLayoutRecords.put(position, rec); } rec.column = lp.column; rec.height = child.getHeight(); rec.id = lp.id; rec.span = Math.min(mColCount, lp.span); } } if (this.mSelectorPosition != INVALID_POSITION) { View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) positionSelector(mMotionPosition, child); } else if (mTouchMode > TOUCH_MODE_DOWN) { View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) positionSelector(mMotionPosition, child); } else { mSelectorRect.setEmpty(); } }
From source file:com.google.android.flexbox.FlexboxHelper.java
/** * Calculates how many flex lines are needed in the flex container layout by measuring each * child./*from w w w .j av a 2 s. c o m*/ * Expanding or shrinking the flex items depending on the flex grow and flex shrink * attributes are done in a later procedure, so the views' measured width and measured * height may be changed in a later process. * * @param result an instance of {@link FlexLinesResult} that is going to contain a * list of flex lines and the child state used by * {@link View#setMeasuredDimension(int, int)}. * @param mainMeasureSpec the main axis measure spec imposed by the flex container, * width for horizontal direction, height otherwise * @param crossMeasureSpec the cross axis measure spec imposed by the flex container, * height for horizontal direction, width otherwise * @param needsCalcAmount the amount of pixels where flex line calculation should be stopped * this is needed to avoid the expensive calculation if the * calculation is needed only the small part of the entire flex * container. (E.g. If the flex container is the * {@link FlexboxLayoutManager}, the calculation only needs the * visible area, imposing the entire calculation may cause bad * performance * @param fromIndex the index of the child from which the calculation starts * @param toIndex the index of the child to which the calculation ends (until the * flex line which include the which who has that index). If this * and needsCalcAmount are both set, first flex lines are calculated * to the index, calculate the amount of pixels as the needsCalcAmount * argument in addition to that * @param existingLines If not null, calculated flex lines will be added to this instance */ void calculateFlexLines(FlexLinesResult result, int mainMeasureSpec, int crossMeasureSpec, int needsCalcAmount, int fromIndex, int toIndex, @Nullable List<FlexLine> existingLines) { boolean isMainHorizontal = mFlexContainer.isMainAxisDirectionHorizontal(); int mainMode = View.MeasureSpec.getMode(mainMeasureSpec); int mainSize = View.MeasureSpec.getSize(mainMeasureSpec); int childState = 0; List<FlexLine> flexLines; if (existingLines == null) { flexLines = new ArrayList<>(); } else { flexLines = existingLines; } result.mFlexLines = flexLines; boolean reachedToIndex = toIndex == NO_POSITION; int mainPaddingStart = getPaddingStartMain(isMainHorizontal); int mainPaddingEnd = getPaddingEndMain(isMainHorizontal); int crossPaddingStart = getPaddingStartCross(isMainHorizontal); int crossPaddingEnd = getPaddingEndCross(isMainHorizontal); int largestSizeInCross = Integer.MIN_VALUE; // The amount of cross size calculated in this method call. int sumCrossSize = 0; // The index of the view in the flex line. int indexInFlexLine = 0; FlexLine flexLine = new FlexLine(); flexLine.mFirstIndex = fromIndex; flexLine.mMainSize = mainPaddingStart + mainPaddingEnd; int childCount = mFlexContainer.getFlexItemCount(); for (int i = fromIndex; i < childCount; i++) { View child = mFlexContainer.getReorderedFlexItemAt(i); if (child == null) { if (isLastFlexItem(i, childCount, flexLine)) { addFlexLine(flexLines, flexLine, i, sumCrossSize); } continue; } else if (child.getVisibility() == View.GONE) { flexLine.mGoneItemCount++; flexLine.mItemCount++; if (isLastFlexItem(i, childCount, flexLine)) { addFlexLine(flexLines, flexLine, i, sumCrossSize); } continue; } FlexItem flexItem = (FlexItem) child.getLayoutParams(); if (flexItem.getAlignSelf() == AlignItems.STRETCH) { flexLine.mIndicesAlignSelfStretch.add(i); } int childMainSize = getFlexItemSizeMain(flexItem, isMainHorizontal); if (flexItem.getFlexBasisPercent() != FLEX_BASIS_PERCENT_DEFAULT && mainMode == View.MeasureSpec.EXACTLY) { childMainSize = Math.round(mainSize * flexItem.getFlexBasisPercent()); // Use the dimension from the layout if the mainMode is not // MeasureSpec.EXACTLY even if any fraction value is set to // layout_flexBasisPercent. } int childMainMeasureSpec; int childCrossMeasureSpec; if (isMainHorizontal) { childMainMeasureSpec = mFlexContainer.getChildWidthMeasureSpec(mainMeasureSpec, mainPaddingStart + mainPaddingEnd + getFlexItemMarginStartMain(flexItem, true) + getFlexItemMarginEndMain(flexItem, true), childMainSize); childCrossMeasureSpec = mFlexContainer.getChildHeightMeasureSpec(crossMeasureSpec, crossPaddingStart + crossPaddingEnd + getFlexItemMarginStartCross(flexItem, true) + getFlexItemMarginEndCross(flexItem, true) + sumCrossSize, getFlexItemSizeCross(flexItem, true)); child.measure(childMainMeasureSpec, childCrossMeasureSpec); updateMeasureCache(i, childMainMeasureSpec, childCrossMeasureSpec, child); } else { childCrossMeasureSpec = mFlexContainer.getChildWidthMeasureSpec(crossMeasureSpec, crossPaddingStart + crossPaddingEnd + getFlexItemMarginStartCross(flexItem, false) + getFlexItemMarginEndCross(flexItem, false) + sumCrossSize, getFlexItemSizeCross(flexItem, false)); childMainMeasureSpec = mFlexContainer.getChildHeightMeasureSpec(mainMeasureSpec, mainPaddingStart + mainPaddingEnd + getFlexItemMarginStartMain(flexItem, false) + getFlexItemMarginEndMain(flexItem, false), childMainSize); child.measure(childCrossMeasureSpec, childMainMeasureSpec); updateMeasureCache(i, childCrossMeasureSpec, childMainMeasureSpec, child); } mFlexContainer.updateViewCache(i, child); // Check the size constraint after the first measurement for the child // To prevent the child's width/height violate the size constraints imposed by the // {@link FlexItem#getMinWidth()}, {@link FlexItem#getMinHeight()}, // {@link FlexItem#getMaxWidth()} and {@link FlexItem#getMaxHeight()} attributes. // E.g. When the child's layout_width is wrap_content the measured width may be // less than the min width after the first measurement. checkSizeConstraints(child, i); childState = View.combineMeasuredStates(childState, child.getMeasuredState()); if (isWrapRequired(child, mainMode, mainSize, flexLine.mMainSize, getViewMeasuredSizeMain(child, isMainHorizontal) + getFlexItemMarginStartMain(flexItem, isMainHorizontal) + getFlexItemMarginEndMain(flexItem, isMainHorizontal), flexItem, i, indexInFlexLine, flexLines.size())) { if (flexLine.getItemCountNotGone() > 0) { addFlexLine(flexLines, flexLine, i > 0 ? i - 1 : 0, sumCrossSize); sumCrossSize += flexLine.mCrossSize; } if (isMainHorizontal) { if (flexItem.getHeight() == ViewGroup.LayoutParams.MATCH_PARENT) { // This case takes care of the corner case where the cross size of the // child is affected by the just added flex line. // E.g. when the child's layout_height is set to match_parent, the height // of that child needs to be determined taking the total cross size used // so far into account. In that case, the height of the child needs to be // measured again note that we don't need to judge if the wrapping occurs // because it doesn't change the size along the main axis. childCrossMeasureSpec = mFlexContainer.getChildHeightMeasureSpec(crossMeasureSpec, mFlexContainer.getPaddingTop() + mFlexContainer.getPaddingBottom() + flexItem.getMarginTop() + flexItem.getMarginBottom() + sumCrossSize, flexItem.getHeight()); child.measure(childMainMeasureSpec, childCrossMeasureSpec); checkSizeConstraints(child, i); } } else { if (flexItem.getWidth() == ViewGroup.LayoutParams.MATCH_PARENT) { // This case takes care of the corner case where the cross size of the // child is affected by the just added flex line. // E.g. when the child's layout_width is set to match_parent, the width // of that child needs to be determined taking the total cross size used // so far into account. In that case, the width of the child needs to be // measured again note that we don't need to judge if the wrapping occurs // because it doesn't change the size along the main axis. childCrossMeasureSpec = mFlexContainer.getChildWidthMeasureSpec(crossMeasureSpec, mFlexContainer.getPaddingLeft() + mFlexContainer.getPaddingRight() + flexItem.getMarginLeft() + flexItem.getMarginRight() + sumCrossSize, flexItem.getWidth()); child.measure(childCrossMeasureSpec, childMainMeasureSpec); checkSizeConstraints(child, i); } } flexLine = new FlexLine(); flexLine.mItemCount = 1; flexLine.mMainSize = mainPaddingStart + mainPaddingEnd; flexLine.mFirstIndex = i; indexInFlexLine = 0; largestSizeInCross = Integer.MIN_VALUE; } else { flexLine.mItemCount++; indexInFlexLine++; } if (mIndexToFlexLine != null) { mIndexToFlexLine[i] = flexLines.size(); } flexLine.mMainSize += getViewMeasuredSizeMain(child, isMainHorizontal) + getFlexItemMarginStartMain(flexItem, isMainHorizontal) + getFlexItemMarginEndMain(flexItem, isMainHorizontal); flexLine.mTotalFlexGrow += flexItem.getFlexGrow(); flexLine.mTotalFlexShrink += flexItem.getFlexShrink(); mFlexContainer.onNewFlexItemAdded(child, i, indexInFlexLine, flexLine); largestSizeInCross = Math.max(largestSizeInCross, getViewMeasuredSizeCross(child, isMainHorizontal) + getFlexItemMarginStartCross(flexItem, isMainHorizontal) + getFlexItemMarginEndCross(flexItem, isMainHorizontal) + mFlexContainer.getDecorationLengthCrossAxis(child)); // Temporarily set the cross axis length as the largest child in the flexLine // Expand along the cross axis depending on the mAlignContent property if needed // later flexLine.mCrossSize = Math.max(flexLine.mCrossSize, largestSizeInCross); if (isMainHorizontal) { if (mFlexContainer.getFlexWrap() != FlexWrap.WRAP_REVERSE) { flexLine.mMaxBaseline = Math.max(flexLine.mMaxBaseline, child.getBaseline() + flexItem.getMarginTop()); } else { // if the flex wrap property is WRAP_REVERSE, calculate the // baseline as the distance from the cross end and the baseline // since the cross size calculation is based on the distance from the cross end flexLine.mMaxBaseline = Math.max(flexLine.mMaxBaseline, child.getMeasuredHeight() - child.getBaseline() + flexItem.getMarginBottom()); } } if (isLastFlexItem(i, childCount, flexLine)) { addFlexLine(flexLines, flexLine, i, sumCrossSize); sumCrossSize += flexLine.mCrossSize; } if (toIndex != NO_POSITION && flexLines.size() > 0 && flexLines.get(flexLines.size() - 1).mLastIndex >= toIndex && i >= toIndex && !reachedToIndex) { // Calculated to include a flex line which includes the flex item having the // toIndex. // Let the sumCrossSize start from the negative value of the last flex line's // cross size because otherwise flex lines aren't calculated enough to fill the // visible area. sumCrossSize = -flexLine.getCrossSize(); reachedToIndex = true; } if (sumCrossSize > needsCalcAmount && reachedToIndex) { // Stop the calculation if the sum of cross size calculated reached to the point // beyond the needsCalcAmount value to avoid unneeded calculation in a // RecyclerView. // To be precise, the decoration length may be added to the sumCrossSize, // but we omit adding the decoration length because even without the decorator // length, it's guaranteed that calculation is done at least beyond the // needsCalcAmount break; } } result.mChildState = childState; }