| 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; } } }