public virtual [email protected] generateOverflowButtonLayoutParams () { [email protected] result = (([email protected] .LayoutParams)generateDefaultLayoutParams()); result.isOverflowButton = true; return(result); }
protected internal override android.view.ViewGroup.LayoutParams generateDefaultLayoutParams () { [email protected] @params = new [email protected] .LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup .LayoutParams.WRAP_CONTENT); @params.gravity = android.view.Gravity.CENTER_VERTICAL; return(@params); }
protected internal override android.view.ViewGroup.LayoutParams generateLayoutParams (android.view.ViewGroup.LayoutParams p) { if (p is [email protected]) { [email protected] result = new [email protected] .LayoutParams(([email protected])p); if (result.gravity <= android.view.Gravity.NO_GRAVITY) { result.gravity = android.view.Gravity.CENTER_VERTICAL; } return(result); } return(([email protected])generateDefaultLayoutParams ()); }
/// <summary>Measure a child view to fit within cell-based formatting.</summary> /// <remarks> /// Measure a child view to fit within cell-based formatting. The child's width /// will be measured to a whole multiple of cellSize. /// <p>Sets the expandable and cellsUsed fields of LayoutParams. /// </remarks> /// <param name="child">Child to measure</param> /// <param name="cellSize">Size of one cell</param> /// <param name="cellsRemaining">Number of cells remaining that this view can expand to fill /// </param> /// <param name="parentHeightMeasureSpec">MeasureSpec used by the parent view</param> /// <param name="parentHeightPadding">Padding present in the parent view</param> /// <returns>Number of cells this child was measured to occupy</returns> internal static int measureChildForCells(android.view.View child, int cellSize, int cellsRemaining, int parentHeightMeasureSpec, int parentHeightPadding) { [email protected] lp = ([email protected] .LayoutParams)child.getLayoutParams(); int childHeightSize = android.view.View.MeasureSpec.getSize(parentHeightMeasureSpec ) - parentHeightPadding; int childHeightMode = android.view.View.MeasureSpec.getMode(parentHeightMeasureSpec ); int childHeightSpec = android.view.View.MeasureSpec.makeMeasureSpec(childHeightSize , childHeightMode); int cellsUsed = 0; if (cellsRemaining > 0) { int childWidthSpec = android.view.View.MeasureSpec.makeMeasureSpec(cellSize * cellsRemaining , android.view.View.MeasureSpec.AT_MOST); child.measure(childWidthSpec, childHeightSpec); int measuredWidth = child.getMeasuredWidth(); cellsUsed = measuredWidth / cellSize; if (measuredWidth % cellSize != 0) { cellsUsed++; } } [email protected] itemView = child is [email protected] ? ([email protected])child : null; bool expandable = !lp.isOverflowButton && itemView != null && itemView.hasText(); lp.expandable = expandable; lp.cellsUsed = cellsUsed; int targetWidth = cellsUsed * cellSize; child.measure(android.view.View.MeasureSpec.makeMeasureSpec(targetWidth, android.view.View .MeasureSpec.EXACTLY), childHeightSpec); return(cellsUsed); }
public LayoutParams([email protected] other ) : base((android.widget.LinearLayout.LayoutParams)other) { isOverflowButton = other.isOverflowButton; }
protected internal override void onLayout(bool changed, int left, int top, int right , int bottom) { if (!mFormatItems) { base.onLayout(changed, left, top, right, bottom); return; } int childCount = getChildCount(); int midVertical = (top + bottom) / 2; int dividerWidth = getDividerWidth(); int overflowWidth = 0; int nonOverflowWidth = 0; int nonOverflowCount = 0; int widthRemaining = right - left - getPaddingRight() - getPaddingLeft(); bool hasOverflow = false; { for (int i = 0; i < childCount; i++) { android.view.View v = getChildAt(i); if (v.getVisibility() == GONE) { continue; } [email protected] p = ([email protected] .LayoutParams)v.getLayoutParams(); if (p.isOverflowButton) { overflowWidth = v.getMeasuredWidth(); if (hasDividerBeforeChildAt(i)) { overflowWidth += dividerWidth; } int height = v.getMeasuredHeight(); int r = getWidth() - getPaddingRight() - p.rightMargin; int l = r - overflowWidth; int t = midVertical - (height / 2); int b = t + height; v.layout(l, t, r, b); widthRemaining -= overflowWidth; hasOverflow = true; } else { int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin; nonOverflowWidth += size; widthRemaining -= size; if (hasDividerBeforeChildAt(i)) { nonOverflowWidth += dividerWidth; } nonOverflowCount++; } } } if (childCount == 1 && !hasOverflow) { // Center a single child android.view.View v = getChildAt(0); int width = v.getMeasuredWidth(); int height = v.getMeasuredHeight(); int midHorizontal = (right - left) / 2; int l = midHorizontal - width / 2; int t = midVertical - height / 2; v.layout(l, t, l + width, t + height); return; } int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1); int spacerSize = System.Math.Max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0); int startLeft = getPaddingLeft(); { for (int i_1 = 0; i_1 < childCount; i_1++) { android.view.View v = getChildAt(i_1); [email protected] lp = ([email protected] .LayoutParams)v.getLayoutParams(); if (v.getVisibility() == GONE || lp.isOverflowButton) { continue; } startLeft += lp.leftMargin; int width = v.getMeasuredWidth(); int height = v.getMeasuredHeight(); int t = midVertical - height / 2; v.layout(startLeft, t, startLeft + width, t + height); startLeft += width + lp.rightMargin + spacerSize; } } }
private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) { // We already know the width mode is EXACTLY if we're here. int heightMode = android.view.View.MeasureSpec.getMode(heightMeasureSpec); int widthSize = android.view.View.MeasureSpec.getSize(widthMeasureSpec); int heightSize = android.view.View.MeasureSpec.getSize(heightMeasureSpec); int widthPadding = getPaddingLeft() + getPaddingRight(); int heightPadding = getPaddingTop() + getPaddingBottom(); widthSize -= widthPadding; // Divide the view into cells. int cellCount = widthSize / mMinCellSize; int cellSizeRemaining = widthSize % mMinCellSize; if (cellCount == 0) { // Give up, nothing fits. setMeasuredDimension(widthSize, 0); return; } int cellSize = mMinCellSize + cellSizeRemaining / cellCount; int cellsRemaining = cellCount; int maxChildHeight = 0; int maxCellsUsed = 0; int expandableItemCount = 0; int visibleItemCount = 0; bool hasOverflow = false; // This is used as a bitfield to locate the smallest items present. Assumes childCount < 64. long smallestItemsAt = 0; int childCount = getChildCount(); { for (int i = 0; i < childCount; i++) { android.view.View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } bool isGeneratedItem = child is [email protected]; visibleItemCount++; if (isGeneratedItem) { // Reset padding for generated menu item views; it may change below // and views are recycled. child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0); } [email protected] lp = ([email protected] .LayoutParams)child.getLayoutParams(); lp.expanded = false; lp.extraPixels = 0; lp.cellsUsed = 0; lp.expandable = false; lp.leftMargin = 0; lp.rightMargin = 0; lp.preventEdgeOffset = isGeneratedItem && (([email protected] )child).hasText(); // Overflow always gets 1 cell. No more, no less. int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining; int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable, heightMeasureSpec , heightPadding); maxCellsUsed = System.Math.Max(maxCellsUsed, cellsUsed); if (lp.expandable) { expandableItemCount++; } if (lp.isOverflowButton) { hasOverflow = true; } cellsRemaining -= cellsUsed; maxChildHeight = System.Math.Max(maxChildHeight, child.getMeasuredHeight()); if (cellsUsed == 1) { smallestItemsAt |= (1 << i); } } } // When we have overflow and a single expanded (text) item, we want to try centering it // visually in the available space even though overflow consumes some of it. bool centerSingleExpandedItem = hasOverflow && visibleItemCount == 2; // Divide space for remaining cells if we have items that can expand. // Try distributing whole leftover cells to smaller items first. bool needsExpansion = false; while (expandableItemCount > 0 && cellsRemaining > 0) { int minCells = int.MaxValue; long minCellsAt = 0; // Bit locations are indices of relevant child views int minCellsItemCount = 0; { for (int i_1 = 0; i_1 < childCount; i_1++) { android.view.View child = getChildAt(i_1); [email protected] lp = ([email protected] .LayoutParams)child.getLayoutParams(); // Don't try to expand items that shouldn't. if (!lp.expandable) { continue; } // Mark indices of children that can receive an extra cell. if (lp.cellsUsed < minCells) { minCells = lp.cellsUsed; minCellsAt = 1 << i_1; minCellsItemCount = 1; } else { if (lp.cellsUsed == minCells) { minCellsAt |= 1 << i_1; minCellsItemCount++; } } } } // Items that get expanded will always be in the set of smallest items when we're done. smallestItemsAt |= minCellsAt; if (minCellsItemCount > cellsRemaining) { break; } // Couldn't expand anything evenly. Stop. // We have enough cells, all minimum size items will be incremented. minCells++; { for (int i_2 = 0; i_2 < childCount; i_2++) { android.view.View child = getChildAt(i_2); [email protected] lp = ([email protected] .LayoutParams)child.getLayoutParams(); if ((minCellsAt & (1 << i_2)) == 0) { // If this item is already at our small item count, mark it for later. if (lp.cellsUsed == minCells) { smallestItemsAt |= 1 << i_2; } continue; } if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) { // Add padding to this item such that it centers. child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0); } lp.cellsUsed++; lp.expanded = true; cellsRemaining--; } } needsExpansion = true; } // Divide any space left that wouldn't divide along cell boundaries // evenly among the smallest items bool singleItem = !hasOverflow && visibleItemCount == 1; if (cellsRemaining > 0 && smallestItemsAt != 0 && (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) { float expandCount = Sharpen.Util.Long_GetBitCount(smallestItemsAt); if (!singleItem) { // The items at the far edges may only expand by half in order to pin to either side. if ((smallestItemsAt & 1) != 0) { [email protected] lp = ([email protected] .LayoutParams)getChildAt(0).getLayoutParams(); if (!lp.preventEdgeOffset) { expandCount -= 0.5f; } } if ((smallestItemsAt & (1 << (childCount - 1))) != 0) { [email protected] lp = (([email protected] .LayoutParams)getChildAt(childCount - 1).getLayoutParams()); if (!lp.preventEdgeOffset) { expandCount -= 0.5f; } } } int extraPixels = expandCount > 0 ? (int)(cellsRemaining * cellSize / expandCount ) : 0; { for (int i_1 = 0; i_1 < childCount; i_1++) { if ((smallestItemsAt & (1 << i_1)) == 0) { continue; } android.view.View child = getChildAt(i_1); [email protected] lp = ([email protected] .LayoutParams)child.getLayoutParams(); if (child is [email protected]) { // If this is one of our views, expand and measure at the larger size. lp.extraPixels = extraPixels; lp.expanded = true; if (i_1 == 0 && !lp.preventEdgeOffset) { // First item gets part of its new padding pushed out of sight. // The last item will get this implicitly from layout. lp.leftMargin = -extraPixels / 2; } needsExpansion = true; } else { if (lp.isOverflowButton) { lp.extraPixels = extraPixels; lp.expanded = true; lp.rightMargin = -extraPixels / 2; needsExpansion = true; } else { // If we don't know what it is, give it some margins instead // and let it center within its space. We still want to pin // against the edges. if (i_1 != 0) { lp.leftMargin = extraPixels / 2; } if (i_1 != childCount - 1) { lp.rightMargin = extraPixels / 2; } } } } } cellsRemaining = 0; } // Remeasure any items that have had extra space allocated to them. if (needsExpansion) { int heightSpec = android.view.View.MeasureSpec.makeMeasureSpec(heightSize - heightPadding , heightMode); { for (int i_1 = 0; i_1 < childCount; i_1++) { android.view.View child = getChildAt(i_1); [email protected] lp = ([email protected] .LayoutParams)child.getLayoutParams(); if (!lp.expanded) { continue; } int width = lp.cellsUsed * cellSize + lp.extraPixels; child.measure(android.view.View.MeasureSpec.makeMeasureSpec(width, android.view.View .MeasureSpec.EXACTLY), heightSpec); } } } if (heightMode != android.view.View.MeasureSpec.EXACTLY) { heightSize = maxChildHeight; } setMeasuredDimension(widthSize, heightSize); mMeasuredExtraWidth = cellsRemaining * cellSize; }
protected internal override android.view.ViewGroup.LayoutParams generateLayoutParams (android.view.ViewGroup.LayoutParams p) { if (p is [email protected]) { [email protected] result = new [email protected] .LayoutParams(([email protected])p); if (result.gravity <= android.view.Gravity.NO_GRAVITY) { result.gravity = android.view.Gravity.CENTER_VERTICAL; } return result; } return (([email protected])generateDefaultLayoutParams ()); }
protected internal override android.view.ViewGroup.LayoutParams generateDefaultLayoutParams () { [email protected] @params = new [email protected] .LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup .LayoutParams.WRAP_CONTENT); @params.gravity = android.view.Gravity.CENTER_VERTICAL; return @params; }