效果如何找出它所附加的 UIImageView 的显示大小?

How can an effect find out the display size of the UIImageView it is attached to?

在 Xamarin.Forms 中,Effect 可以附加到 View。在我的例子中,视图显示 Image。效果是在图像的可见像素周围制作彩色 "glow"。 XAML:

<Image Source="{Binding LogoImage}" ...>
    <Image.Effects>
        <effects:GlowEffect Radius="5" Color="White" />
    </Image.Effects>
</Image>

效果作为RoutingEffect的子类实现:

public class GlowEffect : Xamarin.Forms.RoutingEffect
{
    public GlowEffect() : base("Core.ImageGlowEffect")
    {
    }
...
}

在每个平台上,都有一个PlatformEffect来实现这个效果。对于 iOS:

using ...

[assembly: ExportEffect(typeof(Core.Effects.ImageGlowEffect), "ImageGlowEffect")]
namespace Core.Effects
{
  public class ImageGlowEffect : PlatformEffect
  {
    protected override void OnAttached()
    {
        ApplyGlow();
    }

    protected override void OnElementPropertyChanged( PropertyChangedEventArgs e )
    {
        base.OnElementPropertyChanged( e );

        if (e.PropertyName == "Source") {
            ApplyGlow();
        }
    }

    private void ApplyGlow()
    {
        var imageView = Control as UIImageView;
        if (imageView.Image == null)
            return;

        var effect = (GlowEffect)Element.Effects.FirstOrDefault(e => e is GlowEffect);

        if (effect != null) {
            CGRect outSize = AVFoundation.AVUtilities.WithAspectRatio( new CGRect( new CGPoint(), imageView.Image.Size ), imageView.Frame.Size );
                ...
        }
    }
  ...
  }
}

如果 Source 是动态改变的,上面的代码有效:在 Source 改变时,UIImageViewBoundsFrame)有一个尺寸。但是,如果在 XAML 中静态设置源,则该逻辑不会 运行:因此对 ApplyGlow 的唯一调用是在 OnAttach 期间。不幸的是,在 OnAttach 期间,UIImageView 的大小为 (0, 0)

如何使用静态 Source 在 iOS 上实现此效果?

注意:等效的 Android 效果通过附加到 ImageView.ViewTreeObserver.PreDraw 的处理程序起作用 - 此时大小是已知的。因此,如果存在 iOS 等效事件,那将是一种解决方法。


更多详情:

也许这是一个解决方法,我不知道您是否可以接受。

OnAttached 中调用 ApplyGlow(); 之前添加一点延迟。延迟后,你会得到 imageView.Frame.SizeimageView.Bounds.Size.

protected override async void OnAttached()
{
    await Task.Delay(TimeSpan.FromSeconds(0.3));// it can be 0.2s,0.1s, depending on you
    ApplyGlow();
}

而且如果你设置了WidthRequest,HeightRequest,你可以毫不拖延地到达那里:

private void ApplyGlow()
{
    var imageView = Control as UIImageView;
    if (imageView.Image == null)
        return;

    Console.WriteLine(imageView.Image.Size.Width);
    Console.WriteLine(imageView.Image.Size.Height);

    CoreGraphics.CGSize rect = imageView.Bounds.Size;
    CoreGraphics.CGSize rect2 = imageView.Frame.Size;

    Console.WriteLine(rect);
    Console.WriteLine(rect2);

    double width = (double)Element.GetValue(VisualElement.WidthRequestProperty);
    double height = (double)Element.GetValue(VisualElement.HeightRequestProperty);

    Console.WriteLine(width);
    Console.WriteLine(height);

    double width2 = (double)Element.GetValue(VisualElement.WidthProperty);
    double height2 = (double)Element.GetValue(VisualElement.HeightProperty);

    Console.WriteLine(width2);
    Console.WriteLine(height2);
}