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

ScrollView content needs layout when ScrollView.InvalidateMeasure is called #17639

Merged
merged 5 commits into from Nov 27, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -60,6 +60,38 @@ public async Task TestContentSizeChangedVertical(ScrollOrientation orientation)
});
}

[Fact]
public async Task TestContentHorizontalOptionsChanged()
{
var label = new Label
{
BackgroundColor = Colors.LightBlue,
HorizontalOptions = LayoutOptions.Start,
Text = "Hello",
WidthRequest = 50,
};

var scrollView = new ScrollView
{
BackgroundColor = Colors.DarkBlue,
Content = label,
WidthRequest = 300,
HeightRequest = 200,
};

SetupBuilder();

await AttachAndRun(scrollView, async (handler) =>
{
// Without this delay, the UI didn't render and the bug didn't repro
await Task.Delay(100);

await WaitAssert(() => CloseEnough(scrollView.Content.Frame.Left, 0.0));
scrollView.Content.HorizontalOptions = LayoutOptions.End;
await WaitAssert(() => CloseEnough(scrollView.Content.Frame.Right, 300.0));
});
}

[Theory]
[InlineData(ScrollOrientation.Vertical, 100, 300, 0, 100)]
[InlineData(ScrollOrientation.Horizontal, 0, 100, 100, 300)]
Expand Down Expand Up @@ -188,22 +220,17 @@ static async Task AssertContentSizeChanged(Task<bool> changed)

static async Task AssertContentSize(Func<Size> actual, Size expected)
{
await WaitAssert(() => CloseEnough(actual(), expected, 0.2), timeout: 5000, message: $"ContentSize was {actual()}, expected {expected}");
await WaitAssert(() => CloseEnough(actual(), expected), timeout: 5000, message: $"ContentSize was {actual()}, expected {expected}");
}

static bool CloseEnough(Size a, Size b, double tolerance)
static bool CloseEnough(double a, double b, double tolerance = 0.2)
{
if (System.Math.Abs(a.Width - b.Width) > tolerance)
{
return false;
}

if (System.Math.Abs(a.Height - b.Height) > tolerance)
{
return false;
}
return System.Math.Abs(a - b) <= tolerance;
}

return true;
static bool CloseEnough(Size a, Size b, double tolerance = 0.2)
{
return CloseEnough(a.Width, b.Width, tolerance) && CloseEnough(a.Height, b.Height, tolerance);
}

static Task<bool> WatchContentSizeChanged(ScrollView scrollView)
Expand Down
10 changes: 10 additions & 0 deletions src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs
Expand Up @@ -20,6 +20,16 @@ protected override ScrollViewer CreatePlatformView()
return new ScrollViewer();
}

internal static void MapInvalidateMeasure(IScrollViewHandler handler, IView view, object? args)
{
handler.PlatformView.InvalidateMeasure(view);

if (handler.PlatformView.Content is FrameworkElement content)
{
content.InvalidateMeasure();
spadapet marked this conversation as resolved.
Show resolved Hide resolved
}
}

protected override void ConnectHandler(ScrollViewer platformView)
{
base.ConnectHandler(platformView);
Expand Down
5 changes: 4 additions & 1 deletion src/Core/src/Handlers/ScrollView/ScrollViewHandler.cs
Expand Up @@ -29,7 +29,10 @@ public partial class ScrollViewHandler : IScrollViewHandler

public static CommandMapper<IScrollView, IScrollViewHandler> CommandMapper = new(ViewCommandMapper)
{
[nameof(IScrollView.RequestScrollTo)] = MapRequestScrollTo
[nameof(IScrollView.RequestScrollTo)] = MapRequestScrollTo,
#if WINDOWS
[nameof(IView.InvalidateMeasure)] = MapInvalidateMeasure,
spadapet marked this conversation as resolved.
Show resolved Hide resolved
#endif
};

public ScrollViewHandler() : base(Mapper, CommandMapper)
Expand Down