xamarin 如何在AbsoluteLayout上强制使用方形布局?

os8fio9y  于 2023-08-01  发布在  其他
关注(0)|答案(2)|浏览(115)

有人知道为什么下面的代码在我的窗体应用程序中不执行OnMeasure()吗?我基本上是在尝试强制AbsoluteLayout具有相同的高度/宽度,以显示为Square:

public class AbsoluteSquareLayout : AbsoluteLayout
{
    protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
    {
        var size = Math.Min(widthConstraint, heightConstraint);
        return base.OnMeasure(size, size);
    }
}

字符串

envsm3lx

envsm3lx1#

覆盖OnMeasure调用中的大小约束并不能保证最终大小-因为父布局的最终Layout传递将覆盖此值。XF的文章在这里详细讨论了这一点。
为了能够实现正方形布局-您必须更新父布局以考虑这些约束,并确保它在布局过程中传递。
例如,您可以扩展AbsoluteLayout来动态计算子级的大小约束。默认情况下,此自定义布局将所有子项视为正方形。为了覆盖特定子级的该行为-您可以将附加属性SquareLayout.IsSquare设置为false

public class SquareLayout : AbsoluteLayout
{

    public static readonly BindableProperty IsSquareProperty = 
          BindableProperty.CreateAttached("IsSquare",
                                          typeof(bool),
                                          typeof(SquareLayout),
                                          defaultValue: true,
                                          defaultBindingMode: BindingMode.OneWay);

    public static bool GetIsSquare(BindableObject view)
    {
        return (bool)view.GetValue(IsSquareProperty);
    }

    public static void SetIsSquare(BindableObject view, bool value)
    {
        view.SetValue(IsSquareProperty, value);
    }

    Dictionary<View, Rectangle> _boundsCache = new Dictionary<View, Rectangle>();
    protected override void LayoutChildren(double x, double y, double width, double height)
    {
        foreach(var child in Children)
        {
            var isSquare = GetIsSquare(child);
            if(isSquare)
            {
                Rectangle bounds;
                if (!_boundsCache.ContainsKey(child))
                    _boundsCache[child] = bounds = GetLayoutBounds(child);
                else
                    bounds = _boundsCache[child];

                var absFlags = GetLayoutFlags(child);

                var widthIsProportional = (absFlags & AbsoluteLayoutFlags.WidthProportional) != 0;
                var heightIsProportional = (absFlags & AbsoluteLayoutFlags.HeightProportional) != 0;

                var childWidth = widthIsProportional ? bounds.Width * width : bounds.Width;
                var childHeight = heightIsProportional ? bounds.Height * height : bounds.Height;

                var size = Math.Min(childWidth, childHeight);

                SetLayoutBounds(
                    child,
                    new Rectangle(
                        bounds.X,
                        bounds.Y,
                        (widthIsProportional ? (size / width) : size),
                        (heightIsProportional ? (size / height) : size)
                     )
                );
            }
        }

        base.LayoutChildren(x, y, width, height);
    }
}

字符串

示例用法:

<local:SquareLayout>
    <AbsoluteLayout BackgroundColor="Green" 
                    AbsoluteLayout.LayoutBounds=".1,.1,1,1" 
                    AbsoluteLayout.LayoutFlags="All" />

    <AbsoluteLayout BackgroundColor="Blue" 
                    AbsoluteLayout.LayoutBounds=".5,.5,.2,.1" 
                    AbsoluteLayout.LayoutFlags="All" />

    <AbsoluteLayout BackgroundColor="Red" 
                    AbsoluteLayout.LayoutBounds=".9,.9,200,200" 
                    AbsoluteLayout.LayoutFlags="PositionProportional" />

    <AbsoluteLayout BackgroundColor="Yellow" 
                    AbsoluteLayout.LayoutBounds="10,20,.3,.3" 
                    AbsoluteLayout.LayoutFlags="SizeProportional" />

    <AbsoluteLayout BackgroundColor="Silver" 
                    local:SquareLayout.IsSquare="false"
                    AbsoluteLayout.LayoutBounds=".9,.9,1,.1" 
                    AbsoluteLayout.LayoutFlags="All" />
</local:SquareLayout>

yquaqz18

yquaqz182#

这里有一个解决方案,它涉及一个Frame和一个AbsoluteLayout作为子节点。
Frame将确保AbsoluteLayout居中。

<Frame x:Name="absoluteSquareLayout" BackgroundColor="Transparent">
    <AbsoluteLayout x:Name="absoluteLayout">
    </AbsoluteLayout>
</Frame>

字符串
然后,在后面的代码中,AbsoluteLayout的尺寸是从Frame的尺寸导出的:

public MainPage()
{
    InitializeComponent();
    absoluteSquareLayout.SizeChanged += (s, e) =>
    {
        var size = Math.Min(this.Width, this.Height);
        absoluteLayout.WidthRequest = size;
        absoluteLayout.HeightRequest = size;
    };
}

相关问题