private MeasuredSize measureChild(global::System.IntPtr childPtr, float width, int measureModeWidth, float height, int measureModeHeight) { // We need to measure child layout View child = Registry.GetManagedBaseHandleFromNativePtr(childPtr) as View; LayoutItem childLayout = child.Layout; MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(parentMeasureSpecificationWidth.Size - (child.Margin.Start + child.Margin.End)), parentMeasureSpecificationWidth.Mode), new LayoutLength(Padding.Start + Padding.End), new LayoutLength(child.WidthSpecification)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(parentMeasureSpecificationHeight.Size - (child.Margin.Top + child.Margin.Bottom)), parentMeasureSpecificationHeight.Mode), new LayoutLength(Padding.Top + Padding.Bottom), new LayoutLength(child.HeightSpecification)); childLayout.Measure( childWidthMeasureSpec, childHeightMeasureSpec); return new MeasuredSize(childLayout.MeasuredWidth.Size.AsRoundedValue(),childLayout.MeasuredHeight.Size.AsRoundedValue()); }
/// <summary> /// Ask one of the children of this view to measure itself, taking into /// account both the MeasureSpec requirements for this view and its padding.<br /> /// and margins. The heavy lifting is done in GetChildMeasureSpecification.<br /> /// </summary> /// <param name="child">The child to measure.</param> /// <param name="parentWidthMeasureSpec">The width requirements for this view.</param> /// <param name="widthUsed">Extra space that has been used up by the parent horizontally (possibly by other children of the parent).</param> /// <param name="parentHeightMeasureSpec">The height requirements for this view.</param> /// <param name="heightUsed">Extra space that has been used up by the parent vertically (possibly by other children of the parent).</param> /// <exception cref="ArgumentNullException"> Thrown when child is null. </exception> /// <since_tizen> 6 </since_tizen> protected virtual void MeasureChildWithMargins(LayoutItem child, MeasureSpecification parentWidthMeasureSpec, LayoutLength widthUsed, MeasureSpecification parentHeightMeasureSpec, LayoutLength heightUsed) { if (null == child) { throw new ArgumentNullException(nameof(child)); } View childOwner = child.Owner; Extents margin = childOwner.Margin; MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(parentWidthMeasureSpec.Size + widthUsed - (margin.Start + margin.End)), parentWidthMeasureSpec.Mode), new LayoutLength(Padding.Start + Padding.End), new LayoutLength(childOwner.WidthSpecification)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(parentHeightMeasureSpec.Size + heightUsed - (margin.Top + margin.Bottom)), parentHeightMeasureSpec.Mode), new LayoutLength(Padding.Top + Padding.Bottom), new LayoutLength(childOwner.HeightSpecification)); child.Measure(childWidthMeasureSpec, childHeightMeasureSpec); }
private void MeasureWeightedChild(LayoutItem childLayout, float totalWeightLength, float totalWeight, float childWeight, MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec, HeightAndWidthState childState, Orientation orientation) { bool horizontal = false; if (orientation == Orientation.Horizontal) { horizontal = true; } float childsShare = totalWeightLength * (childWeight / totalWeight); float desiredWidth = childLayout.Owner.WidthSpecification; float desiredHeight = childLayout.Owner.HeightSpecification; MeasureSpecification childWidthMeasureSpec; MeasureSpecification childHeightMeasureSpec; if (horizontal) { childWidthMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Start + childLayout.Margin.End)), MeasureSpecification.ModeType.Exactly); childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)), heightMeasureSpec.Mode), new LayoutLength(Padding.Top + Padding.Bottom), new LayoutLength(desiredHeight)); } else // vertical { childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)), widthMeasureSpec.Mode), new LayoutLength(Padding.Start + Padding.End), new LayoutLength(desiredWidth)); childHeightMeasureSpec = new MeasureSpecification(new LayoutLength(childsShare - (childLayout.Margin.Top + childLayout.Margin.Bottom)), MeasureSpecification.ModeType.Exactly); } childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec); // Child may now not fit in horizontal dimension. if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall) { childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall; } // Child may now not fit in vertical dimension. if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall) { childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall; } }
/// <summary> /// Ask one of the children of this view to measure itself, taking into /// account both the MeasureSpec requirements for this view and its padding.<br /> /// The heavy lifting is done in GetChildMeasureSpec.<br /> /// </summary> /// <param name="child">The child to measure.</param> /// <param name="parentWidthMeasureSpec">The width requirements for this view.</param> /// <param name="parentHeightMeasureSpec">The height requirements for this view.</param> protected virtual void MeasureChild(LayoutItem child, MeasureSpecification parentWidthMeasureSpec, MeasureSpecification parentHeightMeasureSpec) { View childOwner = child.Owner; Extents padding = child.Padding; // Padding of this layout's owner, not of the child being measured. MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(parentWidthMeasureSpec, new LayoutLength(padding.Start + padding.End), new LayoutLength(childOwner.WidthSpecification)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(parentHeightMeasureSpec, new LayoutLength(padding.Top + padding.Bottom), new LayoutLength(childOwner.HeightSpecification)); child.Measure(childWidthMeasureSpec, childHeightMeasureSpec); }
protected void MeasureChildWithoutPadding(LayoutItem child, MeasureSpecification parentWidthMeasureSpec, MeasureSpecification parentHeightMeasureSpec) { View childOwner = child.Owner; MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(parentWidthMeasureSpec.Size), parentWidthMeasureSpec.Mode), new LayoutLength(0), new LayoutLength(childOwner.WidthSpecification)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(parentHeightMeasureSpec.Size), parentHeightMeasureSpec.Mode), new LayoutLength(0), new LayoutLength(childOwner.HeightSpecification)); child.Measure(childWidthMeasureSpec, childHeightMeasureSpec); }
/// <summary> /// Ask one of the children of this view to measure itself, taking into /// account both the MeasureSpec requirements for this view and its padding.<br /> /// The heavy lifting is done in GetChildMeasureSpecification.<br /> /// </summary> /// <param name="child">The child to measure.</param> /// <param name="parentWidthMeasureSpec">The width requirements for this view.</param> /// <param name="parentHeightMeasureSpec">The height requirements for this view.</param> /// <since_tizen> 6 </since_tizen> protected virtual void MeasureChild(LayoutItem child, MeasureSpecification parentWidthMeasureSpec, MeasureSpecification parentHeightMeasureSpec) { View childOwner = child.Owner; MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(parentWidthMeasureSpec.Size), parentWidthMeasureSpec.Mode), new LayoutLength(Padding.Start + Padding.End), new LayoutLength(childOwner.WidthSpecification)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(parentHeightMeasureSpec.Size), parentHeightMeasureSpec.Mode), new LayoutLength(Padding.Top + Padding.Bottom), new LayoutLength(childOwner.HeightSpecification)); child.Measure(childWidthMeasureSpec, childHeightMeasureSpec); }
/// <summary> /// Ask one of the children of this view to measure itself, taking into /// account both the MeasureSpec requirements for this view and its padding.<br /> /// and margins. The child must have MarginLayoutParams The heavy lifting is /// done in GetChildMeasureSpecification.<br /> /// </summary> /// <param name="child">The child to measure.</param> /// <param name="parentWidthMeasureSpec">The width requirements for this view.</param> /// <param name="widthUsed">Extra space that has been used up by the parent horizontally (possibly by other children of the parent).</param> /// <param name="parentHeightMeasureSpec">The height requirements for this view.</param> /// <param name="heightUsed">Extra space that has been used up by the parent vertically (possibly by other children of the parent).</param> protected virtual void MeasureChildWithMargins(LayoutItem child, MeasureSpecification parentWidthMeasureSpec, LayoutLength widthUsed, MeasureSpecification parentHeightMeasureSpec, LayoutLength heightUsed) { View childOwner = child.Owner; int desiredWidth = childOwner.WidthSpecification; int desiredHeight = childOwner.HeightSpecification; Extents padding = child.Padding; // Padding of this layout's owner, not of the child being measured. MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification(parentWidthMeasureSpec, new LayoutLength(padding.Start + padding.End) + widthUsed, new LayoutLength(desiredWidth)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification(parentHeightMeasureSpec, new LayoutLength(padding.Top + padding.Bottom) + heightUsed, new LayoutLength(desiredHeight)); child.Measure(childWidthMeasureSpec, childHeightMeasureSpec); }
/// <summary> /// Ask one of the children of this view to measure itself, taking into /// account both the MeasureSpec requirements for this view and its padding.<br /> /// and margins. The child must have MarginLayoutParams The heavy lifting is /// done in GetChildMeasureSpecification.<br /> /// </summary> /// <param name="child">The child to measure.</param> /// <param name="parentWidthMeasureSpec">The width requirements for this view.</param> /// <param name="widthUsed">Extra space that has been used up by the parent horizontally (possibly by other children of the parent).</param> /// <param name="parentHeightMeasureSpec">The height requirements for this view.</param> /// <param name="heightUsed">Extra space that has been used up by the parent vertically (possibly by other children of the parent).</param> /// <since_tizen> 6 </since_tizen> protected virtual void MeasureChildWithMargins(LayoutItem child, MeasureSpecification parentWidthMeasureSpec, LayoutLength widthUsed, MeasureSpecification parentHeightMeasureSpec, LayoutLength heightUsed) { View childOwner = child.Owner; MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(parentWidthMeasureSpec.Size + widthUsed - (Padding.Start + Padding.End + childOwner.Margin.Start + childOwner.Margin.End)), parentWidthMeasureSpec.Mode), new LayoutLength(Padding.Start + Padding.End), new LayoutLength(childOwner.WidthSpecification)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(parentHeightMeasureSpec.Size + heightUsed - (Padding.Top + Padding.Bottom + childOwner.Margin.Top + childOwner.Margin.Bottom)), parentHeightMeasureSpec.Mode), new LayoutLength(Padding.Top + Padding.Bottom), new LayoutLength(childOwner.HeightSpecification)); child.Measure(childWidthMeasureSpec, childHeightMeasureSpec); }
protected void MeasureChildWithoutPadding(LayoutItem child, MeasureSpecification parentWidthMeasureSpec, MeasureSpecification parentHeightMeasureSpec) { if (null == child) { throw new ArgumentNullException(nameof(child)); } View childOwner = child.Owner; MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(parentWidthMeasureSpec.Size), parentWidthMeasureSpec.Mode), new LayoutLength(0), new LayoutLength(childOwner.WidthSpecification)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(parentHeightMeasureSpec.Size), parentHeightMeasureSpec.Mode), new LayoutLength(0), new LayoutLength(childOwner.HeightSpecification)); child.Measure(childWidthMeasureSpec, childHeightMeasureSpec); }
private void MeasureWeightedChild(LayoutItem childLayout, float remainingExcess, float remainingWeight, float childWeight, MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec, HeightAndWidthState childState, Orientation orientation) { bool horizontal = false; if (orientation == Orientation.Horizontal) { horizontal = true; } float childsShare = (childWeight * remainingExcess) / remainingWeight; remainingExcess -= childsShare; remainingWeight -= childWeight; float desiredWidth = childLayout.Owner.WidthSpecification; float desiredHeight = childLayout.Owner.HeightSpecification; float childLength = 0; // Always lay out weighted elements with intrinsic size regardless of the parent spec. // for consistency between specs. if ((horizontal && (desiredWidth == 0)) || (!horizontal && (desiredHeight == 0))) { // This child needs to be laid out from scratch using // only its share of excess space. childLength = childsShare; } else { // This child had some intrinsic width to which we // need to add its share of excess space. if (horizontal) { childLength = childLayout.MeasuredWidth.Size.AsDecimal() + childsShare; } else { childLength = childLayout.MeasuredHeight.Size.AsDecimal() + childsShare; } } MeasureSpecification childWidthMeasureSpec; MeasureSpecification childHeightMeasureSpec; if (horizontal) { childWidthMeasureSpec = new MeasureSpecification(new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly); childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(heightMeasureSpec.Size - (childLayout.Owner.Margin.Top + childLayout.Owner.Margin.Bottom)), heightMeasureSpec.Mode), new LayoutLength(Padding.Top + Padding.Bottom), new LayoutLength(desiredHeight)); } else // vertical { childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(widthMeasureSpec.Size - (childLayout.Owner.Margin.Start + childLayout.Owner.Margin.End)), widthMeasureSpec.Mode), new LayoutLength(Padding.Start + Padding.End), new LayoutLength(desiredWidth)); childHeightMeasureSpec = new MeasureSpecification(new LayoutLength(childLength), MeasureSpecification.ModeType.Exactly); } childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec); // Child may now not fit in horizontal dimension. if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall) { childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall; } // Child may now not fit in vertical dimension. if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall) { childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall; } }
} // MeasureHorizontal private void MeasureVertical(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec) { var widthMode = widthMeasureSpec.Mode; var heightMode = heightMeasureSpec.Mode; bool isExactly = (heightMode == MeasureSpecification.ModeType.Exactly); bool matchWidth = false; bool allFillParent = true; float maxWidth = 0.0f; float alternativeMaxWidth = 0.0f; float weightedMaxWidth = 0.0f; float totalWeight = 0.0f; // Reset total length _totalLength = 0.0f; float usedExcessSpace = 0.0f; HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK, MeasuredSize.StateType.MeasuredSizeOK); // measure children, and determine if further resolution is required // 1st phase: // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs // to accumulate total used space in _totalLength. // Weighted children are not measured in this phase. // Available space for weighted children will be calculated in the phase 2 based on _totalLength value. for (int i = 0; i < LayoutChildren.Count; i++) { LayoutItem childLayout = LayoutChildren[i]; int childDesiredWidth = childLayout.Owner.WidthSpecification; float childWeight = childLayout.Owner.Weight; Extents childMargin = childLayout.Margin; totalWeight += childWeight; bool useExcessSpace = (childLayout.Owner.HeightSpecification == 0) && (childWeight > 0); if (isExactly && useExcessSpace) { _totalLength = Math.Max(_totalLength, (_totalLength + childMargin.Top + childMargin.Bottom)); } else { if (useExcessSpace) { // The heightMode is either Unspecified or AtMost, and // this child is only laid out using excess space. Measure // using WrapContent so that we can find out the view's // optimal height. // We'll restore the original height of 0 after measurement. MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)), widthMeasureSpec.Mode), new LayoutLength(Padding.Start + Padding.End), new LayoutLength(childDesiredWidth)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)), heightMeasureSpec.Mode), new LayoutLength(Padding.Top + Padding.Bottom), new LayoutLength(LayoutParamPolicies.WrapContent)); childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec); usedExcessSpace += childLayout.MeasuredHeight.Size.AsDecimal(); } else { MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0)); } LayoutLength childHeight = childLayout.MeasuredHeight.Size; LayoutLength length = childHeight + childMargin.Top + childMargin.Bottom; if (isExactly) { _totalLength += length.AsDecimal(); } else { _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + (i < LayoutChildren.Count - 1 ? CellPadding.Height : 0)); } } bool matchWidthLocally = false; if (widthMode != MeasureSpecification.ModeType.Exactly && childDesiredWidth == LayoutParamPolicies.MatchParent) { // Will have to re-measure at least this child when we know exact height. matchWidth = true; matchWidthLocally = true; } float marginWidth = childLayout.Margin.Start + childLayout.Margin.End; float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth; if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall) { childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall; } if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall) { childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall; } maxWidth = Math.Max(maxWidth, childWidth); allFillParent = (allFillParent && childDesiredWidth == LayoutParamPolicies.MatchParent); if (childWeight > 0) { // Widths of weighted Views are bogus if we end up remeasuring, so keep them separate. weightedMaxWidth = Math.Max(weightedMaxWidth, matchWidthLocally ? marginWidth : childWidth); } else { alternativeMaxWidth = Math.Max(alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth); } } // foreach float heightSize = _totalLength; heightSize = Math.Max(heightSize, SuggestedMinimumHeight.AsDecimal()); MeasuredSize heightSizeAndState = ResolveSizeAndState(new LayoutLength(heightSize + Padding.Top + Padding.Bottom), heightMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK); heightSize = heightSizeAndState.Size.AsDecimal(); // 2nd phase: // We cycle through weighted children now (children with weight > 0). // The children are measured with exact size equal to their share of the available space based on their weights. // _totalLength is updated to include weighted children measured sizes. float remainingExcess = heightSize - _totalLength + usedExcessSpace - (Padding.Top + Padding.Bottom); if (remainingExcess != 0 && totalWeight > 0.0f) { float remainingWeight = totalWeight; maxWidth = 0; _totalLength = 0; int numberOfChildren = LayoutChildren.Count; for (int i = 0; i < numberOfChildren; ++i) { LayoutItem childLayout = LayoutChildren[i]; float desiredChildWidth = childLayout.Owner.WidthSpecification; float childWeight = childLayout.Owner.Weight; Extents childMargin = childLayout.Margin; if (childWeight > 0) { MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight, widthMeasureSpec, heightMeasureSpec, childState, Orientation.Vertical); } float length = childLayout.MeasuredHeight.Size.AsDecimal() + childMargin.Top + childMargin.Bottom; float cellPadding = i < numberOfChildren - 1 ? CellPadding.Height : 0; if (isExactly) { _totalLength += length; } else { float totalLength = _totalLength; _totalLength = Math.Max(_totalLength, _totalLength + length + cellPadding); } bool matchWidthLocally = (widthMode != MeasureSpecification.ModeType.Exactly) && (desiredChildWidth == LayoutParamPolicies.MatchParent); float marginWidth = childMargin.Start + childMargin.End; float childWidth = childLayout.MeasuredWidth.Size.AsDecimal() + marginWidth; maxWidth = Math.Max(maxWidth, childWidth); alternativeMaxWidth = Math.Max(alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth); allFillParent = (allFillParent && desiredChildWidth == LayoutParamPolicies.MatchParent); } // for loop } else { alternativeMaxWidth = Math.Max(alternativeMaxWidth, weightedMaxWidth); } if (!allFillParent && widthMode != MeasureSpecification.ModeType.Exactly) { maxWidth = alternativeMaxWidth; } maxWidth += (Owner.WidthSpecification == LayoutParamPolicies.WrapContent)?(Padding.Start + Padding.End):0; maxWidth = Math.Max(maxWidth, SuggestedMinimumWidth.AsRoundedValue()); heightSizeAndState.State = childState.heightState; SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(maxWidth + Padding.Top + Padding.Bottom), widthMeasureSpec, childState.widthState), heightSizeAndState); if (matchWidth) { ForceUniformWidth(heightMeasureSpec); } } // MeasureVertical
private void MeasureHorizontal(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec) { var widthMode = widthMeasureSpec.Mode; var heightMode = heightMeasureSpec.Mode; bool isExactly = (widthMode == MeasureSpecification.ModeType.Exactly); bool matchHeight = false; bool allFillParent = true; float maxHeight = 0.0f; float alternativeMaxHeight = 0.0f; float weightedMaxHeight = 0.0f; float totalWeight = 0.0f; // Reset measure variables _totalLength = 0.0f; float usedExcessSpace = 0.0f; HeightAndWidthState childState = new HeightAndWidthState(MeasuredSize.StateType.MeasuredSizeOK, MeasuredSize.StateType.MeasuredSizeOK); // 1st phase: // We cycle through all children and measure children with weight 0 (non weighted children) according to their specs // to accumulate total used space in totalLength based on measured sizes and margins. // Weighted children are not measured at this phase. // Available space for weighted children will be calculated in the phase 2 based on totalLength value. // Max height of children is stored. for (int i = 0; i < LayoutChildren.Count; i++) { LayoutItem childLayout = LayoutChildren[i]; if (childLayout.Owner.ExcludeLayouting) { MeasureChildWithoutPadding(childLayout, widthMeasureSpec, heightMeasureSpec); continue; } int childDesiredHeight = childLayout.Owner.HeightSpecification; float childWeight = childLayout.Owner.Weight; Extents childMargin = childLayout.Margin; totalWeight += childWeight; bool useExcessSpace = (childLayout.Owner.WidthSpecification == 0) && (childWeight > 0); if (isExactly && useExcessSpace) { // Children to be laid out with excess space can be measured later _totalLength = Math.Max(_totalLength, (_totalLength + childMargin.Start + childMargin.End)); } else { if (useExcessSpace) { // Parent is not defiend!!! // The widthMode is either Unspecified or AtMost, and // this child is only laid out using excess space. Measure // using WrapContent so that we can find out the view's // optimal width. MeasureSpecification childWidthMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(widthMeasureSpec.Size - (childLayout.Margin.Start + childLayout.Margin.End)), widthMeasureSpec.Mode), new LayoutLength(Padding.Start + Padding.End), new LayoutLength(LayoutParamPolicies.WrapContent)); MeasureSpecification childHeightMeasureSpec = GetChildMeasureSpecification( new MeasureSpecification( new LayoutLength(heightMeasureSpec.Size - (childLayout.Margin.Top + childLayout.Margin.Bottom)), heightMeasureSpec.Mode), new LayoutLength(Padding.Top + Padding.Bottom), new LayoutLength(childDesiredHeight)); childLayout.Measure(childWidthMeasureSpec, childHeightMeasureSpec); usedExcessSpace += childLayout.MeasuredWidth.Size.AsDecimal(); } else { MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0)); } LayoutLength childWidth = childLayout.MeasuredWidth.Size; LayoutLength length = childWidth + childMargin.Start + childMargin.End; if (isExactly) { _totalLength += length.AsDecimal(); } else { _totalLength = Math.Max(_totalLength, _totalLength + length.AsDecimal() + (i < LayoutChildren.Count - 1 ? CellPadding.Width : 0)); } } bool matchHeightLocally = false; if (heightMode != MeasureSpecification.ModeType.Exactly && childDesiredHeight == LayoutParamPolicies.MatchParent) { // A child has set to MatchParent on it's height. // Will have to re-measure at least this child when we know exact height. matchHeight = true; matchHeightLocally = true; } float marginHeight = childMargin.Top + childMargin.Bottom; float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight; if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall) { childState.widthState = MeasuredSize.StateType.MeasuredSizeTooSmall; } if (childLayout.MeasuredHeight.State == MeasuredSize.StateType.MeasuredSizeTooSmall) { childState.heightState = MeasuredSize.StateType.MeasuredSizeTooSmall; } maxHeight = Math.Max(maxHeight, childHeight); allFillParent = (allFillParent && childDesiredHeight == LayoutParamPolicies.MatchParent); if (childWeight > 0) { // Heights of weighted Views are invalid if we end up remeasuring, so store them separately. weightedMaxHeight = Math.Max(weightedMaxHeight, matchHeightLocally ? marginHeight : childHeight); } else { alternativeMaxHeight = Math.Max(alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight); } } // foreach float widthSize = _totalLength; widthSize = Math.Max(widthSize, SuggestedMinimumWidth.AsDecimal()); MeasuredSize widthSizeAndState = ResolveSizeAndState(new LayoutLength(widthSize + Padding.Start + Padding.End), widthMeasureSpec, MeasuredSize.StateType.MeasuredSizeOK); widthSize = widthSizeAndState.Size.AsDecimal(); // 2nd phase: // Expand children with weight to take up available space // We cycle through weighted children now (children with weight > 0). // The children are measured with exact size equal to their share of the available space based on their weights. // _totalLength is updated to include weighted children measured sizes. float remainingExcess = widthSize - _totalLength + usedExcessSpace - (Padding.Start + Padding.End); if (remainingExcess != 0 && totalWeight > 0) { float remainingWeight = totalWeight; maxHeight = 0; _totalLength = 0; int numberOfChildren = LayoutChildren.Count; for (int i = 0; i < numberOfChildren; ++i) { LayoutItem childLayout = LayoutChildren[i]; if (childLayout.Owner.ExcludeLayouting) { continue; } float desiredChildHeight = childLayout.Owner.HeightSpecification; float childWeight = childLayout.Owner.Weight; Extents childMargin = childLayout.Margin; if (childWeight > 0) { MeasureWeightedChild(childLayout, remainingExcess, remainingWeight, childWeight, widthMeasureSpec, heightMeasureSpec, childState, Orientation.Horizontal); } float length = childLayout.MeasuredWidth.Size.AsDecimal() + childMargin.Start + childMargin.End; float cellPadding = i < numberOfChildren - 1 ? CellPadding.Width : 0; if (isExactly) { _totalLength += length; } else { float totalLength = _totalLength; _totalLength = Math.Max(_totalLength, _totalLength + length + cellPadding); } bool matchHeightLocally = (heightMode != MeasureSpecification.ModeType.Exactly) && (desiredChildHeight == LayoutParamPolicies.MatchParent); float marginHeight = childMargin.Top + childMargin.Bottom; float childHeight = childLayout.MeasuredHeight.Size.AsDecimal() + marginHeight; maxHeight = Math.Max(maxHeight, childHeight); alternativeMaxHeight = Math.Max(alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight); allFillParent = (allFillParent && desiredChildHeight == LayoutParamPolicies.MatchParent); } // for loop } else { // No excess space or no weighted children alternativeMaxHeight = Math.Max(alternativeMaxHeight, weightedMaxHeight); } if (!allFillParent && heightMode != MeasureSpecification.ModeType.Exactly) { maxHeight = alternativeMaxHeight; } // Padding should be concerned when specification is Wrapcontent. maxHeight += (Owner.HeightSpecification == LayoutParamPolicies.WrapContent) ? (Padding.Top + Padding.Bottom) : 0; maxHeight = Math.Max(maxHeight, SuggestedMinimumHeight.AsRoundedValue()); widthSizeAndState.State = childState.widthState; SetMeasuredDimensions(widthSizeAndState, ResolveSizeAndState(new LayoutLength(maxHeight), heightMeasureSpec, childState.heightState)); if (matchHeight) { ForceUniformHeight(widthMeasureSpec); } } // MeasureHorizontal