Skip to content
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
55 changes: 55 additions & 0 deletions src/Controls/tests/Core.UnitTests/Layouts/FlexLayoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ protected override Size MeasureOverride(double widthConstraint, double heightCon
}
}

class FixedSizeLabel : Label
{
readonly double _width;
readonly double _height;

public FixedSizeLabel(double width, double height)
{
_width = width;
_height = height;
}

protected override Size MeasureOverride(double widthConstraint, double heightConstraint)
{
return new Size(_width, _height);
}
}

[Fact]
public void FlexLayoutMeasuresImagesUnconstrained()
{
Expand Down Expand Up @@ -344,5 +361,43 @@ public void ArrangeOnlyPassFallsBackToDesiredSizeWhenWidthRequestCleared()
var clearedFrame = (flexLayout as IFlexLayout).GetFlexFrame(view as IView);
Assert.Equal(100, clearedFrame.Width);
}

[Fact]
public void GrowItemsPreserveNaturalSizeAndDistributeFreeSpaceEqually_Issue34464()
{
// Items with different natural widths but equal Grow values should each receive
// an equal share of the available free space added on top of their natural width.
// Before the fix, the natural size was zeroed and the inflated flex_dim was
// distributed proportionally, causing items with larger natural sizes to receive
// less growth than smaller items (violating the flex-grow spec).
var root = new Grid();
var controlsFlexLayout = new FlexLayout();
var flexLayout = controlsFlexLayout as IFlexLayout;

// item1 is narrower (50px), item2 is wider (100px); both have equal Grow
var item1 = new FixedSizeLabel(50, 50);
var item2 = new FixedSizeLabel(100, 50);

FlexLayout.SetGrow(item1, 1);
FlexLayout.SetShrink(item1, 0);
FlexLayout.SetGrow(item2, 1);
FlexLayout.SetShrink(item2, 0);

root.Add(controlsFlexLayout);
flexLayout.Add(item1 as IView);
flexLayout.Add(item2 as IView);

// Container = 300px; total natural width = 150px; free space = 150px.
// With Grow=1 on both items each should receive 75px of extra space:
// item1 expected: 50 + 75 = 125
// item2 expected: 100 + 75 = 175
_ = flexLayout.CrossPlatformMeasure(300, 200);

var frame1 = flexLayout.GetFlexFrame(item1 as IView);
var frame2 = flexLayout.GetFlexFrame(item2 as IView);

Assert.Equal(125, frame1.Width);
Assert.Equal(175, frame2.Width);
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 82 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue34464.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.Collections.Generic;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;

namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 34464, "FlexLayout with BindableLayout and Label text display", PlatformAffected.All)]
public class Issue34464 : ContentPage
{
public Issue34464()
{
var items = new List<string>
{
"Some Medium Text",
"Shorter Text",
"Slightly More Text",
"One - Two",
"Two - Four",
"Two - Three",
"One - Eleven",
};

var flexLayout = new FlexLayout
{
Wrap = Microsoft.Maui.Layouts.FlexWrap.Wrap,
AutomationId = "TestFlexLayout"
};

BindableLayout.SetItemsSource(flexLayout, items);
BindableLayout.SetItemTemplate(flexLayout, new DataTemplate(() =>
{
var border = new Border
{
BackgroundColor = Color.FromArgb("#ffcccccc"),
Stroke = Color.FromArgb("#ffb8b8b8"),
Padding = new Thickness(12)
};

FlexLayout.SetGrow(border, 1);
FlexLayout.SetShrink(border, 0);

var backgroundBorder = new Border
{
BackgroundColor = Color.FromArgb("#44ff0000")
};

var label = new Label
{
LineBreakMode = LineBreakMode.NoWrap,
FontSize = 20,
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
TextColor = Color.FromArgb("#ff000000")
};

label.SetBinding(Label.TextProperty, ".");

var grid = new Grid
{
Children = { backgroundBorder, label }
};

border.Content = grid;

return border;
}));

var headerLabel = new Label
{
Text = "FlexLayout with BindableLayout Items:",
FontSize = 16,
Margin = new Thickness(10),
AutomationId = "HeaderLabel"
};

Content = new VerticalStackLayout
{
Children = { headerLabel, flexLayout }
};
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue34464 : _IssuesUITest
{
public Issue34464(TestDevice device) : base(device) { }

public override string Issue => "FlexLayout with BindableLayout and Label text display";

[Test]
[Category(UITestCategories.Layout)]
public void FlexLayoutWithBindableLayoutDisplaysLabels()
{
App.WaitForElement("HeaderLabel");
VerifyScreenshot();
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 7 additions & 2 deletions src/Core/src/Layouts/Flex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -783,10 +783,15 @@ static void layout_items(Item item, int child_begin, int child_end, int children
float flex_size = 0;
if (layout.flex_dim > 0)
{
// Only the free space is distributed proportionally,
// not the total container space. layout.flex_dim was inflated by extra_flex_dim
// (the sum of measured sizes of growing items), so we recover the actual free
// space by subtracting it back. The item's measured size is preserved and the
// proportional share of free space is added on top.
float freeSpace = Math.Max(0, layout.flex_dim - layout.extra_flex_dim);
if (child.Grow != 0)
{
child.Frame[layout.frame_size_i] = 0; // Ignore previous size when growing.
flex_size = (layout.flex_dim / layout.flex_grows) * child.Grow;
flex_size = (freeSpace / layout.flex_grows) * child.Grow;
}
}
else if (layout.flex_dim < 0)
Expand Down
Loading