Skip to content

Commit

Permalink
When measuring FlexLayout unconstrained, allow child to be desired si…
Browse files Browse the repository at this point in the history
…ze (#13216)

* When measuring FlexLayout unconstrained, allow child to be desired size (rather than zero)
Fixes #11909

* Fix issue on Windows with HorizontalStackLayout

* De-duplicate some test code
  • Loading branch information
hartez authored Feb 13, 2023
1 parent 442c126 commit 9b59594
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/Controls/src/Core/Layout/FlexLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,14 @@ void AddFlexItem(IView child)
{
if (_root == null)
return;

if (child is not BindableObject)
{
// If this is a pure Core IView, we need to track all the flex properties
// locally because we don't have attached properties for them
_viewInfo.Add(child, new FlexInfo());
}

var item = (child as FlexLayout)?._root ?? new Flex.Item();
InitItemProperties(child, item);
if (child is not FlexLayout)
Expand Down
49 changes: 49 additions & 0 deletions src/Controls/tests/Core.UnitTests/Layouts/FlexLayoutTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Layouts;
using Xunit;
using NSubstitute;

namespace Microsoft.Maui.Controls.Core.UnitTests.Layouts
{
Expand Down Expand Up @@ -80,5 +81,53 @@ public void FlexLayoutRecognizesVisibilityChange()
// now that the first view is not visible
Assert.True(whenInvisible != whenVisible);
}

/*
* These next two tests deal with unconstrained measure of FlexLayout. Be default, FL
* wants to stretch children across each axis. But you can't stretch things across infinity
* without it getting weird. So for _measurement_ purposes, we treat infinity as zero and
* just give the children their desired size in the unconstrained direction. Otherwise, FL
* would just set their flex frame sizes to zero, which can either cause blanks or layout cycles,
* depending on the target platform.
*/

(IFlexLayout, IView) SetUpUnconstrainedTest()
{
var root = new Grid(); // FlexLayout requires a parent, at least for now
var flexLayout = new FlexLayout() as IFlexLayout;

var view = Substitute.For<IView>();
var size = new Size(100, 100);
view.Measure(Arg.Any<double>(), Arg.Any<double>()).Returns(size);

root.Add(flexLayout);
flexLayout.Add(view);

return (flexLayout, view);
}

[Fact]
public void UnconstrainedHeightChildrenHaveHeight()
{
(var flexLayout, var view) = SetUpUnconstrainedTest();

_ = flexLayout.CrossPlatformMeasure(400, double.PositiveInfinity);

var flexFrame = flexLayout.GetFlexFrame(view);

Assert.Equal(100, flexFrame.Height);
}

[Fact]
public void UnconstrainedWidthChildrenHaveWidth()
{
(var flexLayout, var view) = SetUpUnconstrainedTest();

_ = flexLayout.CrossPlatformMeasure(double.PositiveInfinity, 400);

var flexFrame = flexLayout.GetFlexFrame(view);

Assert.Equal(100, flexFrame.Width);
}
}
}
35 changes: 35 additions & 0 deletions src/Controls/tests/DeviceTests/Elements/Layout/LayoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
using Xunit;
using Xunit.Sdk;

namespace Microsoft.Maui.DeviceTests
{
Expand Down Expand Up @@ -151,5 +153,38 @@ static void CreateLayout(Type layoutType, out Layout layout, out Label label)
layout.Add(label);
}
}

[Fact, Category(TestCategory.FlexLayout)]
public async Task FlexLayoutInVerticalStackLayoutDoesNotCycle()
{
await FlexLayoutInStackLayoutDoesNotCycle(new VerticalStackLayout());
}

[Fact, Category(TestCategory.FlexLayout)]
public async Task FlexLayoutInHorizontalStackLayoutDoesNotCycle()
{
await FlexLayoutInStackLayoutDoesNotCycle(new HorizontalStackLayout());
}

async Task FlexLayoutInStackLayoutDoesNotCycle(IStackLayout root)
{
var flexLayout = new FlexLayout();
var label = new Label { Text = "Hello" };

flexLayout.Add(label);
root.Add(flexLayout);

await InvokeOnMainThreadAsync(async () =>
{
var labelHandler = CreateHandler<LabelHandler>(label);
var flexLayoutHandler = CreateHandler<LayoutHandler>(flexLayout);
var layoutHandler = CreateHandler<LayoutHandler>(root);

// If this can be attached to the hierarchy and make it through a layout
// without crashing, then we're good.

await root.ToPlatform(MauiContext).AttachAndRun(() => { });
});
}
}
}
3 changes: 2 additions & 1 deletion src/Controls/tests/DeviceTests/TestCategory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ public static class TestCategory
public const string Editor = "Editor";
public const string Element = "Element";
public const string Entry = "Entry";
public const string Frame = "Frame";
public const string FlexLayout = "FlexLayout";
public const string FlyoutPage = "FlyoutPage";
public const string Frame = "Frame";
public const string Gesture = "Gesture";
public const string Image = "Image";
public const string Label = "Label";
Expand Down
10 changes: 8 additions & 2 deletions src/Core/src/Layouts/Flex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ static void layout_item(Item item, float width, float height)
for (int j = 0; j < 2; j++)
{
int size_off = j + 2;
if (size_off == layout.frame_size2_i && child_align(child, item) == AlignItems.Stretch)
if (size_off == layout.frame_size2_i && child_align(child, item) == AlignItems.Stretch && layout.align_dim > 0)
continue;
float val = size[j];
if (!float.IsNaN(val))
Expand Down Expand Up @@ -579,7 +579,13 @@ static void layout_item(Item item, float width, float height)
layout.flex_grows += child.Grow;
layout.flex_shrinks += child.Shrink;

layout.flex_dim -= child_size + child.MarginThickness(layout.vertical);
if(layout.flex_dim > 0)
{
// If flex_dim is zero, it's because we're measuring unconstrained in that direction
// So we don't need to keep a running tally of available space

layout.flex_dim -= child_size + child.MarginThickness(layout.vertical);
}

relative_children_count++;

Expand Down

0 comments on commit 9b59594

Please sign in to comment.