From e44c057d6e29855802f721bbb920cd9ac1ca164e Mon Sep 17 00:00:00 2001 From: Jakub Florkowski Date: Sun, 12 Jan 2025 18:55:25 +0100 Subject: [PATCH] ScrollView CrossPlatformMeasure - refactor --- .../ScrollView/ScrollViewHandler.Android.cs | 23 ++++++++-------- .../ScrollView/ScrollViewHandler.Windows.cs | 27 +++++++++---------- .../ScrollView/ScrollViewHandler.iOS.cs | 27 +------------------ src/Core/src/Layouts/LayoutExtensions.cs | 25 +++++++++++++++++ 4 files changed, 49 insertions(+), 53 deletions(-) diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Android.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Android.cs index 3a8a4b3e9741..b037d6844e9b 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Android.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Android.cs @@ -219,7 +219,10 @@ static void InsertInsetView(IScrollViewHandler handler, IScrollView scrollView, Size ICrossPlatformLayout.CrossPlatformMeasure(double widthConstraint, double heightConstraint) { - var scrollView = VirtualView; + if (VirtualView is not { } scrollView) + { + return Size.Zero; + } var padding = scrollView.Padding; @@ -228,26 +231,22 @@ Size ICrossPlatformLayout.CrossPlatformMeasure(double widthConstraint, double he return new Size(padding.HorizontalThickness, padding.VerticalThickness); } - // Exclude the padding while measuring the internal content ... - var measurementWidth = widthConstraint - padding.HorizontalThickness; - var measurementHeight = heightConstraint - padding.VerticalThickness; - - var result = (scrollView as ICrossPlatformLayout).CrossPlatformMeasure(measurementWidth, measurementHeight); - - // ... and add the padding back in to the final result - var fullSize = new Size(result.Width + padding.HorizontalThickness, result.Height + padding.VerticalThickness); + var scrollOrientation = scrollView.Orientation; + var contentWidthConstraint = scrollOrientation is ScrollOrientation.Horizontal or ScrollOrientation.Both ? double.PositiveInfinity : widthConstraint; + var contentHeightConstraint = scrollOrientation is ScrollOrientation.Vertical or ScrollOrientation.Both ? double.PositiveInfinity : heightConstraint; + var contentSize = scrollView.MeasureContent(scrollView.Padding, contentWidthConstraint, contentHeightConstraint, !double.IsInfinity(contentWidthConstraint), !double.IsInfinity(contentHeightConstraint)); if (double.IsInfinity(widthConstraint)) { - widthConstraint = result.Width; + widthConstraint = contentSize.Width; } if (double.IsInfinity(heightConstraint)) { - heightConstraint = result.Height; + heightConstraint = contentSize.Height; } - return fullSize.AdjustForFill(new Rect(0, 0, widthConstraint, heightConstraint), scrollView.PresentedContent); + return contentSize.AdjustForFill(new Rect(0, 0, widthConstraint, heightConstraint), scrollView.PresentedContent); } Size ICrossPlatformLayout.CrossPlatformArrange(Rect bounds) diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs index 0309f84bb32e..bb71662ad698 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Windows.cs @@ -164,37 +164,34 @@ static void InsertContentPanel(ScrollViewer scrollViewer, IScrollView scrollView Size ICrossPlatformLayout.CrossPlatformMeasure(double widthConstraint, double heightConstraint) { - var scrollView = VirtualView; + if (VirtualView is not { } scrollView) + { + return Size.Zero; + } var padding = scrollView.Padding; - var presentedContent = scrollView.PresentedContent; - if (presentedContent == null) + if (scrollView.PresentedContent == null) { return new Size(padding.HorizontalThickness, padding.VerticalThickness); } - // Exclude the padding while measuring the internal content ... - var measurementWidth = widthConstraint - padding.HorizontalThickness; - var measurementHeight = heightConstraint - padding.VerticalThickness; - - var result = (scrollView as ICrossPlatformLayout).CrossPlatformMeasure(measurementWidth, measurementHeight); - - // ... and add the padding back in to the final result - var fullSize = new Size(result.Width + padding.HorizontalThickness, result.Height + padding.VerticalThickness); + var scrollOrientation = scrollView.Orientation; + var contentWidthConstraint = scrollOrientation is ScrollOrientation.Horizontal or ScrollOrientation.Both ? double.PositiveInfinity : widthConstraint; + var contentHeightConstraint = scrollOrientation is ScrollOrientation.Vertical or ScrollOrientation.Both ? double.PositiveInfinity : heightConstraint; + var contentSize = scrollView.MeasureContent(scrollView.Padding, contentWidthConstraint, contentHeightConstraint, !double.IsInfinity(contentWidthConstraint), !double.IsInfinity(contentHeightConstraint)); if (double.IsInfinity(widthConstraint)) { - widthConstraint = result.Width; + widthConstraint = contentSize.Width; } if (double.IsInfinity(heightConstraint)) { - heightConstraint = result.Height; + heightConstraint = contentSize.Height; } - // If the presented content has LayoutAlignment Fill, we'll need to adjust the measurement to account for that - return fullSize.AdjustForFill(new Rect(0, 0, widthConstraint, heightConstraint), presentedContent); + return contentSize.AdjustForFill(new Rect(0, 0, widthConstraint, heightConstraint), scrollView.PresentedContent); } Size ICrossPlatformLayout.CrossPlatformArrange(Rect bounds) diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs index b08737d8b093..e6206040fb31 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.iOS.cs @@ -154,7 +154,7 @@ Size ICrossPlatformLayout.CrossPlatformMeasure(double widthConstraint, double he var scrollOrientation = scrollView.Orientation; var contentWidthConstraint = scrollOrientation is ScrollOrientation.Horizontal or ScrollOrientation.Both ? double.PositiveInfinity : widthConstraint; var contentHeightConstraint = scrollOrientation is ScrollOrientation.Vertical or ScrollOrientation.Both ? double.PositiveInfinity : heightConstraint; - var contentSize = MeasureContent(scrollView, scrollView.Padding, contentWidthConstraint, contentHeightConstraint); + var contentSize = scrollView.MeasureContent(scrollView.Padding, contentWidthConstraint, contentHeightConstraint, !double.IsInfinity(contentWidthConstraint), !double.IsInfinity(contentHeightConstraint)); // Our target size is the smaller of it and the constraints var width = contentSize.Width <= widthConstraint ? contentSize.Width : widthConstraint; @@ -166,31 +166,6 @@ Size ICrossPlatformLayout.CrossPlatformMeasure(double widthConstraint, double he return new Size(width, height); } - static Size MeasureContent(IContentView contentView, Thickness inset, double widthConstraint, double heightConstraint) - { - var content = contentView.PresentedContent; - - var contentSize = Size.Zero; - - if (!double.IsInfinity(widthConstraint) && Dimension.IsExplicitSet(contentView.Width)) - { - widthConstraint = contentView.Width; - } - - if (!double.IsInfinity(heightConstraint) && Dimension.IsExplicitSet(contentView.Height)) - { - heightConstraint = contentView.Height; - } - - if (content is not null) - { - contentSize = content.Measure(widthConstraint - inset.HorizontalThickness, - heightConstraint - inset.VerticalThickness); - } - - return new Size(contentSize.Width + inset.HorizontalThickness, contentSize.Height + inset.VerticalThickness); - } - Size ICrossPlatformLayout.CrossPlatformArrange(Rect bounds) { return (VirtualView as ICrossPlatformLayout)?.CrossPlatformArrange(bounds) ?? Size.Zero; diff --git a/src/Core/src/Layouts/LayoutExtensions.cs b/src/Core/src/Layouts/LayoutExtensions.cs index 1eb6d05fdcf0..ab49fc4dec70 100644 --- a/src/Core/src/Layouts/LayoutExtensions.cs +++ b/src/Core/src/Layouts/LayoutExtensions.cs @@ -167,6 +167,31 @@ public static Size MeasureContent(this IContentView contentView, Thickness inset return new Size(contentSize.Width + inset.HorizontalThickness, contentSize.Height + inset.VerticalThickness); } + internal static Size MeasureContent(this IContentView contentView, Thickness inset, double widthConstraint, double heightConstraint, bool constrainPresentedContentWidthToExplicitDimsOnContentView, bool constrainPresentedContentHeightToExplicitDimsOnContentView) + { + var content = contentView.PresentedContent; + + if (Dimension.IsExplicitSet(contentView.Width) && constrainPresentedContentWidthToExplicitDimsOnContentView) + { + widthConstraint = contentView.Width; + } + + if (Dimension.IsExplicitSet(contentView.Height) && constrainPresentedContentHeightToExplicitDimsOnContentView) + { + heightConstraint = contentView.Height; + } + + var contentSize = Size.Zero; + + if (content != null) + { + contentSize = content.Measure(widthConstraint - inset.HorizontalThickness, + heightConstraint - inset.VerticalThickness); + } + + return new Size(contentSize.Width + inset.HorizontalThickness, contentSize.Height + inset.VerticalThickness); + } + public static void ArrangeContent(this IContentView contentView, Rect bounds) { if (contentView.PresentedContent == null)