File: Layouts\AbsoluteLayoutManager.cs
Web Access
Project: src\src\Core\src\Core.csproj (Microsoft.Maui)
using System;
using Microsoft.Maui.Graphics;
 
namespace Microsoft.Maui.Layouts
{
	public class AbsoluteLayoutManager : LayoutManager
	{
		public IAbsoluteLayout AbsoluteLayout { get; }
 
		const double AutoSize = -1;
 
		public AbsoluteLayoutManager(IAbsoluteLayout absoluteLayout) : base(absoluteLayout)
		{
			AbsoluteLayout = absoluteLayout;
		}
 
		public override Size Measure(double widthConstraint, double heightConstraint)
		{
			var padding = AbsoluteLayout.Padding;
 
			var availableWidth = widthConstraint - padding.HorizontalThickness;
			var availableHeight = heightConstraint - padding.VerticalThickness;
 
			double measuredHeight = 0;
			double measuredWidth = 0;
 
			for (int n = 0; n < AbsoluteLayout.Count; n++)
			{
				var child = AbsoluteLayout[n];
 
				if (child.Visibility == Visibility.Collapsed)
				{
					continue;
				}
 
				var bounds = AbsoluteLayout.GetLayoutBounds(child);
				var flags = AbsoluteLayout.GetLayoutFlags(child);
				bool isWidthProportional = HasFlag(flags, AbsoluteLayoutFlags.WidthProportional);
				bool isHeightProportional = HasFlag(flags, AbsoluteLayoutFlags.HeightProportional);
 
				var measureWidth = ResolveChildMeasureConstraint(bounds.Width, isWidthProportional, widthConstraint);
				var measureHeight = ResolveChildMeasureConstraint(bounds.Height, isHeightProportional, heightConstraint);
 
				var measure = child.Measure(measureWidth, measureHeight);
 
				var width = ResolveDimension(isWidthProportional, bounds.Width, availableWidth, measure.Width);
				var height = ResolveDimension(isHeightProportional, bounds.Height, availableHeight, measure.Height);
 
				measuredHeight = Math.Max(measuredHeight, bounds.Top + height);
				measuredWidth = Math.Max(measuredWidth, bounds.Left + width);
			}
 
			var finalHeight = ResolveConstraints(heightConstraint, AbsoluteLayout.Height, measuredHeight, AbsoluteLayout.MinimumHeight, AbsoluteLayout.MaximumHeight);
			var finalWidth = ResolveConstraints(widthConstraint, AbsoluteLayout.Width, measuredWidth, AbsoluteLayout.MinimumWidth, AbsoluteLayout.MaximumWidth);
 
			return new Size(finalWidth, finalHeight);
		}
 
		public override Size ArrangeChildren(Rect bounds)
		{
			var padding = AbsoluteLayout.Padding;
 
			double top = padding.Top + bounds.Top;
			double left = padding.Left + bounds.Left;
			double availableWidth = bounds.Width - padding.HorizontalThickness;
			double availableHeight = bounds.Height - padding.VerticalThickness;
 
			for (int n = 0; n < AbsoluteLayout.Count; n++)
			{
				var child = AbsoluteLayout[n];
 
				if (child.Visibility == Visibility.Collapsed)
				{
					continue;
				}
 
				var destination = AbsoluteLayout.GetLayoutBounds(child);
				var flags = AbsoluteLayout.GetLayoutFlags(child);
 
				bool isWidthProportional = HasFlag(flags, AbsoluteLayoutFlags.WidthProportional);
				bool isHeightProportional = HasFlag(flags, AbsoluteLayoutFlags.HeightProportional);
 
				destination.Width = ResolveDimension(isWidthProportional, destination.Width, availableWidth, child.DesiredSize.Width);
				destination.Height = ResolveDimension(isHeightProportional, destination.Height, availableHeight, child.DesiredSize.Height);
 
				if (HasFlag(flags, AbsoluteLayoutFlags.XProportional))
				{
					destination.X = (availableWidth - destination.Width) * destination.X;
				}
 
				if (HasFlag(flags, AbsoluteLayoutFlags.YProportional))
				{
					destination.Y = (availableHeight - destination.Height) * destination.Y;
				}
 
				destination.X += left;
				destination.Y += top;
 
				child.Arrange(destination);
			}
 
			return new Size(availableWidth, availableHeight);
		}
 
		static bool HasFlag(AbsoluteLayoutFlags a, AbsoluteLayoutFlags b)
		{
			// Avoiding Enum.HasFlag here for performance reasons; we don't need the type check
			return (a & b) == b;
		}
 
		static double ResolveDimension(bool isProportional, double fromBounds, double available, double measured)
		{
			// By default, we use the absolute value from LayoutBounds
			var value = fromBounds;
 
			if (isProportional && !double.IsInfinity(available))
			{
				// If this dimension is marked proportional, then the value is a percentage of the available space
				// Multiple it by the available space to figure out the final value
				value *= available;
			}
			else if (value == AutoSize)
			{
				// No absolute or proportional value specified, so we use the measured value
				value = measured;
			}
 
			return value;
		}
 
		static double ResolveChildMeasureConstraint(double boundsValue, bool proportional, double constraint)
		{
			if (boundsValue < 0)
			{
				// If the child view doesn't have bounds set by the AbsoluteLayout, then we'll let it auto-size
				return double.PositiveInfinity;
			}
 
			if (proportional)
			{
				return boundsValue * constraint;
			}
 
			return boundsValue;
		}
	}
}