[NUI] Fix to measure GridLayout's children sizes correctly
authorJaehyun Cho <jae_hyun.cho@samsung.com>
Wed, 18 Aug 2021 12:54:00 +0000 (21:54 +0900)
committerhuiyu <35286162+huiyueun@users.noreply.github.com>
Tue, 7 Sep 2021 09:05:39 +0000 (18:05 +0900)
Previously, if child's measured size is 0, then GridLayout does not
update the child's measured size when the child's size is set by using
GridLayout APIs.
e.g.
SetHorizontalStretch(child, GridLayout.StretchFlags.ExpandAndFill);

Moreover, if child has its own size and ExpandAndFill is set, then
child's size is set to be its own size (its measured size) plus its
expanded size.
e.g.
parent size is 100.
child1's measured size is 50 and ExpandAndFill.
child2's measured size is 0 and ExpandAndFill.
Then, child1's size is 50 + 25 = 75 and child2's size is 25.

To resolve the above, GridLayout updates child's measured size in
OnLayout() and child's size is set to be the bigger one between its
measured size and its expanded size.

src/Tizen.NUI/src/internal/Layouting/GridLocations.cs
src/Tizen.NUI/src/public/Layouting/GridLayout.cs

index d3f9d6c..66fac24 100755 (executable)
@@ -293,9 +293,20 @@ namespace Tizen.NUI
 
             for (int i = 0; i < edgeList.Length; i++)
             {
-                float newLocation = locations[edgeList[i].Start] + edgeList[i].Edge + edgeList[i].ExpandedSize;
-                if (edgeList[i].Edge + edgeList[i].ExpandedSize > 0)
-                    newLocation += space;
+                float newLocation = locations[edgeList[i].Start];
+                // view's size is set to be the bigger one between its measured size and its expanded size.
+                if (edgeList[i].Edge > edgeList[i].ExpandedSize)
+                {
+                    newLocation += edgeList[i].Edge;
+                    if (edgeList[i].Edge > 0)
+                        newLocation += space;
+                }
+                else
+                {
+                    newLocation += edgeList[i].ExpandedSize;
+                    if (edgeList[i].ExpandedSize > 0)
+                        newLocation += space;
+                }
 
                 if (locations[edgeList[i].End] < newLocation)
                 {
index 03f8e33..fb11baf 100755 (executable)
@@ -415,19 +415,64 @@ namespace Tizen.NUI
                 float t = vLocations[row] + Padding.Top + view.Margin.Top;
                 float width = hLocations[columnEnd] - hLocations[column] - ColumnSpacing - view.Margin.Start - view.Margin.End;
                 float height = vLocations[rowEnd] - vLocations[row] - RowSpacing - view.Margin.Top - view.Margin.Bottom;
+                bool needMeasuredWidth = false;
+                bool needMeasuredHeight = false;
 
-                if (!child.Column.Stretch.HasFlag(StretchFlags.Fill))
+                if (child.Column.Stretch.HasFlag(StretchFlags.Fill))
+                {
+                    needMeasuredWidth = true;
+                }
+                else
                 {
                     l += (width - child.LayoutItem.MeasuredWidth.Size.AsDecimal()) * halign.ToFloat();
                     width = child.LayoutItem.MeasuredWidth.Size.AsDecimal();
                 }
 
-                if (!child.Row.Stretch.HasFlag(StretchFlags.Fill))
+                if (child.Row.Stretch.HasFlag(StretchFlags.Fill))
+                {
+                    needMeasuredHeight = true;
+                }
+                else
                 {
                     t += (height - child.LayoutItem.MeasuredHeight.Size.AsDecimal()) * valign.ToFloat();
                     height = child.LayoutItem.MeasuredHeight.Size.AsDecimal();
                 }
 
+                if (needMeasuredWidth || needMeasuredHeight)
+                {
+                    // To calculate the grand children's Measure() with the mode type Exactly,
+                    // children's Measure() is called with MatchParent if the children have WrapContent.
+                    //
+                    // i.e.
+                    // If children have Wrapcontent and the grand children have MatchParent,
+                    // then grand children's MeasuredWidth/Height do not fill the children
+                    // because the grand children's Measure() is called with the mode type AtMost.
+                    int widthSpecification = child.LayoutItem.Owner.WidthSpecification;
+                    int heightSpecification = child.LayoutItem.Owner.HeightSpecification;
+
+                    if (needMeasuredWidth)
+                    {
+                        child.LayoutItem.Owner.WidthSpecification = LayoutParamPolicies.MatchParent;
+                    }
+                    if (needMeasuredHeight)
+                    {
+                        child.LayoutItem.Owner.HeightSpecification = LayoutParamPolicies.MatchParent;
+                    }
+
+                    MeasureSpecification widthSpec = new MeasureSpecification(new LayoutLength(width), MeasureSpecification.ModeType.Exactly);
+                    MeasureSpecification heightSpec = new MeasureSpecification(new LayoutLength(height), MeasureSpecification.ModeType.Exactly);
+                    MeasureChild(child.LayoutItem, widthSpec, heightSpec);
+
+                    if (needMeasuredWidth)
+                    {
+                        child.LayoutItem.Owner.WidthSpecification = widthSpecification;
+                    }
+                    if (needMeasuredHeight)
+                    {
+                        child.LayoutItem.Owner.HeightSpecification = heightSpecification;
+                    }
+                }
+
                 child.LayoutItem.Layout(new LayoutLength(l), new LayoutLength(t), new LayoutLength(l + width), new LayoutLength(t + height));
             }
         }