Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix edge case with Grids, *s, and unconstrained layouts #14114

Merged
merged 2 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/Core/src/Layouts/GridLayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,13 @@ double AvailableHeight(Cell cell)

public void DecompressStars(Size targetSize)
{
if (_grid.VerticalLayoutAlignment == LayoutAlignment.Fill || Dimension.IsExplicitSet(_explicitGridHeight))
bool decompressVertical = Dimension.IsExplicitSet(_explicitGridHeight)
|| _grid.VerticalLayoutAlignment == LayoutAlignment.Fill && targetSize.Height > MeasuredGridHeight();

bool decompressHorizontal = Dimension.IsExplicitSet(_explicitGridWidth)
|| _grid.HorizontalLayoutAlignment == LayoutAlignment.Fill && targetSize.Width > MeasuredGridWidth();

if (decompressVertical)
{
// Reset the size on all star rows
ZeroOutStarSizes(_rows);
Expand All @@ -758,7 +764,7 @@ public void DecompressStars(Size targetSize)
ResolveStarRows(targetSize.Height, true);
}

if (_grid.HorizontalLayoutAlignment == LayoutAlignment.Fill || Dimension.IsExplicitSet(_explicitGridWidth))
if (decompressHorizontal)
{
// Reset the size on all star columns
ZeroOutStarSizes(_columns);
Expand Down
88 changes: 79 additions & 9 deletions src/Core/tests/UnitTests/Layouts/GridLayoutManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1936,7 +1936,7 @@ public void StarColumnWidthCorrectWhenFirstChildCollapsed()

[Fact("ArrangeChildren should arranged within measured size")]
[Category(GridStarSizing)]
public void ArrangeChildrenShouldArrangedWithinMeasuredSize()
public void ArrangeChildrenShouldArrangeWithinMeasuredSize()
{
var grid = CreateGridLayout(rows: "*");
grid.Width.Returns(105);
Expand All @@ -1953,7 +1953,7 @@ public void ArrangeChildrenShouldArrangedWithinMeasuredSize()
AssertArranged(view0, 0, 0, measuredSize.Width, measuredSize.Height);
}

[Theory]
[Theory, Category(GridStarSizing)]
[InlineData(LayoutAlignment.Center, true)]
[InlineData(LayoutAlignment.Center, false)]
[InlineData(LayoutAlignment.Start, true)]
Expand All @@ -1980,7 +1980,7 @@ public void GridMeasuresStarColumnToChildWidth(LayoutAlignment alignment, bool i
Assert.Equal(20, measuredSize.Width);
}

[Theory]
[Theory, Category(GridStarSizing)]
[InlineData(true, 100)]
[InlineData(false, 100)]
[InlineData(true, 15)]
Expand All @@ -2002,7 +2002,7 @@ public void FillGridArrangesStarColumnToWidthConstraint(bool implied, double con
AssertArranged(view0, new Rect(0, 0, constraint, 100));
}

[Theory]
[Theory, Category(GridStarSizing)]
[InlineData(LayoutAlignment.Center, true)]
[InlineData(LayoutAlignment.Center, false)]
[InlineData(LayoutAlignment.Start, true)]
Expand All @@ -2029,7 +2029,7 @@ public void NonFillGridArrangesStarColumnToChildWidth(LayoutAlignment alignment,
AssertArranged(view0, new Rect(0, 0, 20, 100));
}

[Theory]
[Theory, Category(GridStarSizing)]
[InlineData(LayoutAlignment.Center, true)]
[InlineData(LayoutAlignment.Center, false)]
[InlineData(LayoutAlignment.Start, true)]
Expand All @@ -2056,7 +2056,7 @@ public void GridMeasuresStarRowToChildHeight(LayoutAlignment alignment, bool imp
Assert.Equal(20, measuredSize.Height);
}

[Theory]
[Theory, Category(GridStarSizing)]
[InlineData(true, 100)]
[InlineData(false, 100)]
[InlineData(true, 15)]
Expand All @@ -2078,7 +2078,7 @@ public void FillGridArrangesStarRowToHeightConstraint(bool implied, double const
AssertArranged(view0, new Rect(0, 0, 100, constraint));
}

[Theory]
[Theory, Category(GridStarSizing)]
[InlineData(LayoutAlignment.Center, true)]
[InlineData(LayoutAlignment.Center, false)]
[InlineData(LayoutAlignment.Start, true)]
Expand All @@ -2104,7 +2104,7 @@ public void NonFillGridArrangesStarRowToChildHeight(LayoutAlignment alignment, b
AssertArranged(view0, new Rect(0, 0, 100, 20));
}

[Fact]
[Fact, Category(GridStarSizing)]
public void StarRowsResizeWhenGridExpandsToFill()
{
var grid = CreateGridLayout(rows: "*");
Expand All @@ -2130,7 +2130,7 @@ public void StarRowsResizeWhenGridExpandsToFill()
AssertArranged(view0, new Rect(0, 0, 20, 100));
}

[Fact]
[Fact, Category(GridStarSizing)]
public void StarColumnsResizeWhenGridExpandsToFill()
{
var grid = CreateGridLayout(columns: "*");
Expand Down Expand Up @@ -2427,5 +2427,75 @@ public void AutoStarRowsRespectUnconstrainedWidth()
// be arranged at the top left corner
AssertArranged(view0, new Rect(0, 0, 20, 20));
}

[Fact, Category(GridStarSizing)]
public void UnconstrainedStarRowsRetainTheirHeightsWhenArrangedAtMeasuredSize()
{
// This test accounts for the situation where a Grid has Rows marked as "*", is measured
// without height constraint, is vertically set to Fill, and is arranged at the measured height.
// Basically, a situation where the Grid is inside a vertically-oriented ScrollView or StackLayout,
// and the concept of vertical "Fill" doesn't mean anything. In that situation, the rows should
// retain their automatic sizing, rather than being evenly distributed as usual.

var grid = CreateGridLayout(rows: "*, *, *");
grid.VerticalLayoutAlignment.Returns(LayoutAlignment.Fill);

var view0 = CreateTestView(new Size(20, 20));
var view1 = CreateTestView(new Size(20, 40));
var view2 = CreateTestView(new Size(20, 60));

SubstituteChildren(grid, view0, view1, view2);

SetLocation(grid, view0, row: 0);
SetLocation(grid, view1, row: 1);
SetLocation(grid, view2, row: 2);

// Measure the Grid with no height constraint, then arrange it using the resulting size
// Unconstrained, we expect the views to total 20 + 40 + 60 = 120 height
// Since we're arranging it at that same height, there's reason for it to expand the items
// so we expect them to be arranged at the same heights
var measure = MeasureAndArrange(grid, widthConstraint: 200, heightConstraint: double.PositiveInfinity);

Assert.Equal(120, measure.Height);

AssertArranged(view0, new Rect(0, 0, 20, 20));
AssertArranged(view1, new Rect(0, 20, 20, 40));
AssertArranged(view2, new Rect(0, 60, 20, 60));
}

[Fact, Category(GridStarSizing)]
public void UnconstrainedStarColumnsRetainTheirWidthsWhenArrangedAtMeasuredSize()
{
// This test accounts for the situation where a Grid has Columns marked as "*", is measured
// without width constraint, is horizontally set to Fill, and is arranged at the measured width.
// Basically, a situation where the Grid is inside a horizontally-oriented ScrollView or StackLayout,
// and the concept of horizontal "Fill" doesn't mean anything. In that situation, the columns should
// retain their automatic sizing, rather than being evenly distributed as usual.

var grid = CreateGridLayout(columns: "*, *, *");
grid.HorizontalLayoutAlignment.Returns(LayoutAlignment.Fill);

var view0 = CreateTestView(new Size(20, 20));
var view1 = CreateTestView(new Size(40, 20));
var view2 = CreateTestView(new Size(60, 20));

SubstituteChildren(grid, view0, view1, view2);

SetLocation(grid, view0, col: 0);
SetLocation(grid, view1, col: 1);
SetLocation(grid, view2, col: 2);

// Measure the Grid with no width constraint, then arrange it using the resulting size
// Unconstrained, we expect the views to total 20 + 40 + 60 = 120 width
// Since we're arranging it at that same width, there's reason for it to expand the items
// so we expect them to be arranged at the same widths
var measure = MeasureAndArrange(grid, widthConstraint: double.PositiveInfinity, heightConstraint: 200);

Assert.Equal(120, measure.Width);

AssertArranged(view0, new Rect(0, 0, 20, 20));
AssertArranged(view1, new Rect(20, 00, 40, 20));
AssertArranged(view2, new Rect(60, 0, 60, 20));
}
}
}