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; int childrenCount = IterateLayoutChildren().Count(); // 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. foreach (LayoutItem childLayout in IterateLayoutChildren()) { 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 defined!!! // 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; totalLength = Math.Max(totalLength, totalLength + length.AsDecimal()); } 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 totalLength = Math.Max(totalLength, totalLength + CellPadding.Width * (childrenCount - 1)); 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; foreach (LayoutItem childLayout in IterateLayoutChildren()) { 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; totalLength += length; 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 totalLength = Math.Max(totalLength, totalLength + CellPadding.Width * (childrenCount - 1)); } 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
/// <summary> /// Performs the layouting positioning /// </summary> private void PerformLayout(View root, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom) { root.Layout?.Layout(left, top, right, bottom); }
/// <summary> /// Layout should assign a size and position to each of its children.<br /> /// </summary> /// <param name="changed">This is a new size or position for this layout.</param> /// <param name="left">Left position, relative to parent.</param> /// <param name="top"> Top position, relative to parent.</param> /// <param name="right">Right position, relative to parent.</param> /// <param name="bottom">Bottom position, relative to parent.</param> /// <since_tizen> 6 </since_tizen> protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom) { if (linearOrientation == Orientation.Horizontal) { LayoutHorizontal(left, top, right, bottom); } else { LayoutVertical(left, top, right, bottom); } }
// Starts of the actual measuring and layouting from the given root node. // Can be called from multiple starting roots but in series. void MeasureAndLayout(View root) { if (root != null) { // Get parent MeasureSpecification, this could be the Window or View with an exact size. Container parentNode = root.GetParent(); Size2D rootSize; Position2D rootPosition = root.Position2D; View parentView = parentNode as View; if (parentView) { // Get parent View's Size. If using Legacy size negotiation then should have been set already. rootSize = new Size2D(parentView.Size2D.Width, parentView.Size2D.Height); } else { // Parent not a View so assume it's a Layer which is the size of the window. rootSize = new Size2D(_window.Size.Width, _window.Size.Height); } // Determine measure specification for root. // The root layout policy could be an exact size, be match parent or wrap children. // If wrap children then at most it can be the root parent size. // If match parent then should be root parent size. // If exact then should be that size limited by the root parent size. LayoutLength width = new LayoutLength(rootSize.Width); LayoutLength height = new LayoutLength(rootSize.Height); MeasureSpecification.ModeType widthMode = MeasureSpecification.ModeType.AtMost; MeasureSpecification.ModeType heightMode = MeasureSpecification.ModeType.AtMost; if (root.WidthSpecification >= 0) { // exact size provided so match width exactly width = new LayoutLength(root.WidthSpecification); widthMode = MeasureSpecification.ModeType.Exactly; } else if (root.WidthSpecification == LayoutParamPolicies.MatchParent) { widthMode = MeasureSpecification.ModeType.Exactly; } if (root.HeightSpecification >= 0) { // exact size provided so match height exactly height = new LayoutLength(root.HeightSpecification); heightMode = MeasureSpecification.ModeType.Exactly; } else if (root.HeightSpecification == LayoutParamPolicies.MatchParent) { heightMode = MeasureSpecification.ModeType.Exactly; } MeasureSpecification parentWidthSpecification = new MeasureSpecification(width, widthMode); MeasureSpecification parentHeightSpecification = new MeasureSpecification(height, heightMode); // Start at root with it's parent's widthSpecification and heightSpecification MeasureHierarchy(root, parentWidthSpecification, parentHeightSpecification); // Start at root which was just measured. PerformLayout(root, new LayoutLength(rootPosition.X), new LayoutLength(rootPosition.Y), new LayoutLength(rootPosition.X) + root.Layout.MeasuredWidth.Size, new LayoutLength(rootPosition.Y) + root.Layout.MeasuredHeight.Size); bool readyToPlay = SetupCoreAnimation(); if (readyToPlay && OverrideCoreAnimation == false) { PlayAnimation(); } } }
/// <summary> /// Assign a size and position to each of its children.<br /> /// </summary> /// <param name="changed">This is a new size or position for this layout.</param> /// <param name="left">Left position, relative to parent.</param> /// <param name="top"> Top position, relative to parent.</param> /// <param name="right">Right position, relative to parent.</param> /// <param name="bottom">Bottom position, relative to parent.</param> /// <since_tizen> 6 </since_tizen> protected override void OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom ) { bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL; LayoutLength width = right - left; LayoutLength height = bottom - top; // Call to FlexLayout implementation to calculate layout values for later retrieval. Interop.FlexLayout.FlexLayout_CalculateLayout( swigCPtr, width.AsDecimal(), height.AsDecimal(), isLayoutRtl ); int count = LayoutChildren.Count; for( int childIndex = 0; childIndex < count; childIndex++) { LayoutItem childLayout = LayoutChildren[childIndex]; if( childLayout != null ) { // Get the frame for the child, start, top, end, bottom. Vector4 frame = new Vector4(Interop.FlexLayout.FlexLayout_GetNodeFrame(swigCPtr, childIndex ), true); childLayout.Layout( new LayoutLength(frame.X), new LayoutLength(frame.Y), new LayoutLength(frame.Z), new LayoutLength(frame.W) ); } } }
/// <summary> /// Called from Layout() when this layout should assign a size and position to each of its children. <br /> /// Derived classes with children should override this method and call Layout() on each of their children. <br /> /// </summary> /// <param name="changed">This is a new size or position for this layout.</param> /// <param name="left">Left position, relative to parent.</param> /// <param name="top">Top position, relative to parent.</param> /// <param name="right">Right position, relative to parent.</param> /// <param name="bottom">Bottom position, relative to parent.</param> protected virtual void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom) { }
} // LayoutHorizontally private void LayoutVertical(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom) { LayoutLength childTop = new LayoutLength(Padding.Top); LayoutLength childLeft = new LayoutLength(Padding.Start); // Where end of child should go LayoutLength width = new LayoutLength(right - left); // Space available for child LayoutLength childSpace = new LayoutLength(width - Padding.Start - Padding.End); int count = LayoutChildren.Count; switch (LinearAlignment) { case Alignment.Bottom: // totalLength contains the padding already childTop = new LayoutLength(Padding.Top + bottom.AsDecimal() - top.AsDecimal() - totalLength); break; case Alignment.CenterVertical: // FALL THROUGH case Alignment.Center: // totalLength contains the padding already childTop = new LayoutLength(Padding.Top + (bottom.AsDecimal() - top.AsDecimal() - totalLength) / 2.0f); break; case Alignment.Top: // FALL THROUGH (default) default: // totalLength contains the padding already childTop = new LayoutLength(Padding.Top); break; } for (int i = 0; i < count; i++) { LayoutItem childLayout = LayoutChildren[i]; if (childLayout != null) { LayoutLength childWidth = childLayout.MeasuredWidth.Size; LayoutLength childHeight = childLayout.MeasuredHeight.Size; Extents childMargin = childLayout.Margin; childTop += childMargin.Top; switch (LinearAlignment) { case Alignment.Begin: default: { childLeft = new LayoutLength(Padding.Start + childMargin.Start); break; } case Alignment.End: { childLeft = new LayoutLength(width - Padding.End - childWidth - childMargin.End); break; } case Alignment.CenterHorizontal: case Alignment.Center: // FALL THROUGH { childLeft = new LayoutLength(Padding.Start + ((childSpace - childWidth).AsDecimal() / 2.0f) + childMargin.Start - childMargin.End); break; } } childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); childTop += childHeight + childMargin.Bottom + ((i < count - 1) ? CellPadding.Height : 0); } } } // LayoutVertical
} // MeasureVertical private void LayoutHorizontal(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom) { bool isLayoutRtl = Owner.LayoutDirection == ViewLayoutDirectionType.RTL; LayoutLength childTop = new LayoutLength(Padding.Top); LayoutLength childLeft = new LayoutLength(Padding.Start); // Where bottom of child should go LayoutLength height = new LayoutLength(bottom - top); // Space available for child LayoutLength childSpace = new LayoutLength(height - Padding.Top - Padding.Bottom); int count = LayoutChildren.Count; switch (LinearAlignment) { case Alignment.End: // totalLength contains the padding already // In case of RTL map END alignment to the left edge if (isLayoutRtl) { childLeft = new LayoutLength(Padding.Start); } else { childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength); } break; case Alignment.CenterHorizontal: // FALL THROUGH case Alignment.Center: // totalLength contains the padding already childLeft = new LayoutLength(Padding.Start + (right.AsDecimal() - left.AsDecimal() - totalLength) / 2.0f); break; case Alignment.Begin: // FALL THROUGH (default) default: // totalLength contains the padding already // In case of RTL map BEGIN alignment to the right edge if (isLayoutRtl) { childLeft = new LayoutLength(Padding.Start + right.AsDecimal() - left.AsDecimal() - totalLength); } else { childLeft = new LayoutLength(Padding.Start); } break; } int start = 0; int dir = 1; // In case of RTL, start drawing from the last child. if (isLayoutRtl) { start = count - 1; dir = -1; } for (int i = 0; i < count; i++) { int childIndex = start + dir * i; // Get a reference to the childLayout at the given index LayoutItem childLayout = LayoutChildren[childIndex]; if (childLayout != null) { LayoutLength childWidth = childLayout.MeasuredWidth.Size; LayoutLength childHeight = childLayout.MeasuredHeight.Size; Extents childMargin = childLayout.Margin; switch (LinearAlignment) { case Alignment.Bottom: childTop = new LayoutLength(height - Padding.Bottom - childHeight - childMargin.Bottom); break; case Alignment.CenterVertical: case Alignment.Center: // FALLTHROUGH childTop = new LayoutLength(Padding.Top + ((childSpace - childHeight).AsDecimal() / 2.0f) + childMargin.Top - childMargin.Bottom); break; case Alignment.Top: // FALLTHROUGH default default: childTop = new LayoutLength(Padding.Top + childMargin.Top); break; } childLeft += childMargin.Start; childLayout.Layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); childLeft += childWidth + childMargin.End + ((i < count - 1) ? CellPadding.Width : 0); } } } // LayoutHorizontally
} // 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 = this.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
/// <inheritdoc/> /// <since_tizen> 9 </since_tizen> protected override void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom) { for (int i = 0; i < LayoutChildren.Count; i++) { LayoutItem childLayout = LayoutChildren[i]; if (childLayout != null) { Geometry horizontalGeometry = GetHorizontalLayout(childLayout.Owner); Geometry verticalGeometry = GetVerticalLayout(childLayout.Owner); // MeasureChildWithMargins() is called to assign child's MeasuredWidth/Height to calculate grand children's sizes correctly. // Grand children's positions are calculated correctly only if their sizes are calculated correctly. // MeasureChildWithMargins() should be called before childLayout.Layout() to use childLayout's MeasuredWidth/Height // when the grand children's positions are calculated. // // FIXME: It would be better if MeasureChildWithMargins() are called in OnMeasure() to separate Measure and Layout calculations. // For now, not to call duplicate GetHorizontalLayout() and GetVerticalLayout() in both OnMeasure() and OnLayout(), // MeasureChildWithMargins() is called here. MeasureChildWithMargins(childLayout, new MeasureSpecification(new LayoutLength(horizontalGeometry.Size), MeasureSpecification.ModeType.Exactly), new LayoutLength(0), new MeasureSpecification(new LayoutLength(verticalGeometry.Size), MeasureSpecification.ModeType.Exactly), new LayoutLength(0)); LayoutLength childLeft = new LayoutLength(horizontalGeometry.Position + Padding.Start + childLayout.Margin.Start); LayoutLength childRight = new LayoutLength(horizontalGeometry.Position + horizontalGeometry.Size + Padding.Start - childLayout.Margin.End); LayoutLength childTop = new LayoutLength(verticalGeometry.Position + Padding.Top + childLayout.Margin.Top); LayoutLength childBottom = new LayoutLength(verticalGeometry.Position + verticalGeometry.Size + Padding.Top - childLayout.Margin.Bottom); childLayout.Layout(childLeft, childTop, childRight, childBottom); } } HorizontalRelativeCache.Clear(); VerticalRelativeCache.Clear(); }