From 1acbf8c24046849fbbc8a0462d763e31bebebf0a Mon Sep 17 00:00:00 2001 From: Jaehyun Cho Date: Mon, 7 Jun 2021 22:02:25 +0900 Subject: [PATCH] [NUI] Fix RelativeLayout's descendant size and position calculations Previously, 2 descendant sizes and positions calculation problems exitsted on RelativeLayout as follows. 1. MatchParent grand children's sizes and positions were not calculated. - RelativeLayout set its children's sizes and positions but it did not set its children's MeasuredWidth/Height. - If children's MeasuredWidth/Height are not set, then the MatchParent grand children's sizes and positions are not calculated. 2. MatchParent children's sizes fill to the RelativeLayout by default. - MatchParent children's sizes should not fill to the RelativeLayout by default because children's sizes and positions should be calculated by RelativeLayout's APIs. Now, the above problems have been fixed as follows. 1. RelativeLayout sets its children's MeasuredWidth/Height, so its MatchParent grand children's sizes and positions are calculated correctly. 2. MatchParent children's sizes are calculated by RelativeLayout's APIs. --- src/Tizen.NUI/src/public/Layouting/LinearLayout.cs | 42 ++++++++++++++++++---- .../src/public/Layouting/RelativeLayout.cs | 35 +++++++++++++++++- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/src/Tizen.NUI/src/public/Layouting/LinearLayout.cs b/src/Tizen.NUI/src/public/Layouting/LinearLayout.cs index f986536..2b171b9 100755 --- a/src/Tizen.NUI/src/public/Layouting/LinearLayout.cs +++ b/src/Tizen.NUI/src/public/Layouting/LinearLayout.cs @@ -354,7 +354,12 @@ namespace Tizen.NUI { needToMeasure = true; } - else + // RelativeLayout's MatchParent children should not fill to the RelativeLayout. + // Because the children's sizes and positions are calculated by RelativeLayout's APIs. + // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost. + // + // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent. + else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent) { if (childDesiredHeight == LayoutParamPolicies.MatchParent) { @@ -378,7 +383,12 @@ namespace Tizen.NUI widthMeasureSpec.SetSize(new LayoutLength((int)(remainingWidth / childrenMatchParentCount) + Padding.Start + Padding.End)); needToMeasure = true; } - else + // RelativeLayout's MatchParent children should not fill to the RelativeLayout. + // Because the children's sizes and positions are calculated by RelativeLayout's APIs. + // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost. + // + // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent. + else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent) { if (childDesiredWidth == LayoutParamPolicies.MatchParent) { @@ -432,7 +442,12 @@ namespace Tizen.NUI widthMeasureSpec, heightMeasureSpec, childState, Orientation.Horizontal); } - else + // RelativeLayout's MatchParent children should not fill to the RelativeLayout. + // Because the children's sizes and positions are calculated by RelativeLayout's APIs. + // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost. + // + // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent. + else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent) { if (childDesiredWidth == LayoutParamPolicies.MatchParent) { @@ -572,7 +587,12 @@ namespace Tizen.NUI { needToMeasure = true; } - else + // RelativeLayout's MatchParent children should not fill to the RelativeLayout. + // Because the children's sizes and positions are calculated by RelativeLayout's APIs. + // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost. + // + // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent. + else if (Owner.WidthSpecification == LayoutParamPolicies.WrapContent) { if (childDesiredWidth == LayoutParamPolicies.MatchParent) { @@ -596,7 +616,12 @@ namespace Tizen.NUI heightMeasureSpec.SetSize(new LayoutLength((int)(remainingHeight / childrenMatchParentCount) + Padding.Top + Padding.Bottom)); needToMeasure = true; } - else + // RelativeLayout's MatchParent children should not fill to the RelativeLayout. + // Because the children's sizes and positions are calculated by RelativeLayout's APIs. + // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost. + // + // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent. + else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent) { if (childDesiredHeight == LayoutParamPolicies.MatchParent) { @@ -650,7 +675,12 @@ namespace Tizen.NUI widthMeasureSpec, heightMeasureSpec, childState, Orientation.Vertical); } - else + // RelativeLayout's MatchParent children should not fill to the RelativeLayout. + // Because the children's sizes and positions are calculated by RelativeLayout's APIs. + // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost. + // + // Not to print the recursive reference error message for this case, Specification is checked if it is WrapContent. + else if (Owner.HeightSpecification == LayoutParamPolicies.WrapContent) { if (childDesiredHeight == LayoutParamPolicies.MatchParent) { diff --git a/src/Tizen.NUI/src/public/Layouting/RelativeLayout.cs b/src/Tizen.NUI/src/public/Layouting/RelativeLayout.cs index c78e17f..ed8ea33 100755 --- a/src/Tizen.NUI/src/public/Layouting/RelativeLayout.cs +++ b/src/Tizen.NUI/src/public/Layouting/RelativeLayout.cs @@ -348,7 +348,28 @@ namespace Tizen.NUI LayoutItem childLayout = LayoutChildren[i]; if (childLayout != null) { - MeasureChildWithMargins(childLayout, widthMeasureSpec, new LayoutLength(0), heightMeasureSpec, new LayoutLength(0)); + var childWidthMeasureSpec = new MeasureSpecification(widthMeasureSpec.Size, widthMeasureSpec.Mode); + var childHeightMeasureSpec = new MeasureSpecification(heightMeasureSpec.Size, heightMeasureSpec.Mode); + + // RelativeLayout's MatchParent children should not fill to the RelativeLayout. + // Because the children's sizes and positions are calculated by RelativeLayout's APIs. + // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost. + if (childLayout.Owner.WidthSpecification == LayoutParamPolicies.MatchParent) + { + childWidthMeasureSpec.SetSize(new LayoutLength(widthMeasureSpec.Size)); + childWidthMeasureSpec.SetMode(MeasureSpecification.ModeType.AtMost); + } + + // RelativeLayout's MatchParent children should not fill to the RelativeLayout. + // Because the children's sizes and positions are calculated by RelativeLayout's APIs. + // Therefore, not to fill the RelativeLayout, the mode is changed from Exactly to AtMost. + if (childLayout.Owner.HeightSpecification == LayoutParamPolicies.MatchParent) + { + childHeightMeasureSpec.SetSize(new LayoutLength(heightMeasureSpec.Size)); + childHeightMeasureSpec.SetMode(MeasureSpecification.ModeType.AtMost); + } + + MeasureChildWithMargins(childLayout, childWidthMeasureSpec, new LayoutLength(0), childHeightMeasureSpec, new LayoutLength(0)); if (childLayout.MeasuredWidth.State == MeasuredSize.StateType.MeasuredSizeTooSmall) { @@ -378,6 +399,18 @@ namespace Tizen.NUI 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); -- 2.7.4