2017-10-12 68 views
0

任何人都知道为什么下面的代码不会在我的Forms应用程序中执行OnMeasure()?基本上,我试图迫使AbsoluteLayout具有相同的高度/宽度显示为一个广场:在OnMeasure通话如何在我的AbsoluteLayout上强制正方形布局?

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

回答

1

重写尺寸的限制并不能保证最终大小 - 从父母最终Layout通布局将覆盖此值。 XF文章here对此进行了详细的讨论。

为了能够实现方形布局 - 您将不得不更新父布局以考虑这些约束,并确保它在布局传递中传递。

例如,您可以扩展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> 

enter image description here enter image description here

+0

哇很好的解释!感谢您的理解:) – Maximus