title: How can an effect find out the display size of the UIImageView it is attached to?
body: <p>In Xamarin.Forms, an <a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/effects/" rel="nofollow noreferrer"><code>Effect</code></a> can be attached to a <code>View</code>. In my case, the View is displaying an <code>Image</code>. And the effect is making a colored "glow" around the visible pixels of the image. XAML:</p>
  
  <pre><code>&lt;Image Source="{Binding LogoImage}" ...&gt;
      &lt;Image.Effects&gt;
          &lt;effects:GlowEffect Radius="5" Color="White" /&gt;
      &lt;/Image.Effects&gt;
  &lt;/Image&gt;
  </code></pre>
  
  <p>The effect is implemented as a subclass of <code>RoutingEffect</code>:</p>
  
  <pre><code>public class GlowEffect : Xamarin.Forms.RoutingEffect
  {
      public GlowEffect() : base("Core.ImageGlowEffect")
      {
      }
  ...
  }
  </code></pre>
  
  <p>On each platform, there is a <code>PlatformEffect</code> to implement the effect. For iOS:</p>
  
  <pre><code>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 =&gt; e is GlowEffect);
  
          if (effect != null) {
              CGRect outSize = AVFoundation.AVUtilities.WithAspectRatio( new CGRect( new CGPoint(), imageView.Image.Size ), imageView.Frame.Size );
                  ...
          }
      }
    ...
    }
  }
  </code></pre>
  
  <p>The above code works if <code>Source</code> is changed dynamically: at the time <code>Source</code> changes, the <code>UIImageView</code> (<code>Bounds</code> or <code>Frame</code>) has a size. BUT if the Source is set statically in XAML, that logic does not run: so the only call to <code>ApplyGlow</code> is during <code>OnAttach</code>. UNFORTUNATELY, during <code>OnAttach</code>, the <code>UIImageView</code> has size <code>(0, 0)</code>.</p>
  
  <p><strong>How get this effect to work on iOS, with a static <code>Source</code>?</strong></p>
  
  <p>NOTE: The equivalent Android effect works via a handler attached to <code>ImageView.ViewTreeObserver.PreDraw</code> - at which time the size is known. So if there is an iOS equivalent event, that would be one way to solve.</p>
  
  <hr>
  
  <p>More Details:</p>
  
  <ul>
  <li><p>The original implementation used the original image size (imageView.Image.Size) - which is available during <code>OnAttach</code>. This can be made to "work", but is not satisfactory: the glow is applied to the full size image. If the image is significantly larger than the view area, the glow becomes much too small a radius (iOS shrinks the image+glow as it renders): it does not have the desired appearance.</p></li>
  <li><p><code>ApplyGlow</code> has an option to apply a tint color to the image. That tint color is different than the glow color. I mention this because it restricts the possible solutions: AFAIK, can't just set options on an image and let iOS figure out how to render it - need to explicitly resize the image and draw the resized tinted image on top of a blurred version (the glow). This code all works - <em>if</em> <code>imageView.Bounds.Size</code> (or <code>imageView.Frame.Size</code>) is available (and non-zero).</p></li>
  <li><p>With a breakpoint in <code>OnElementPropertyChanged</code>, I've checked to see if imageView size is known for any property that is always set. No; if no properties are dynamically set, the property changes all occur before imageView has a size.</p></li>
  </ul>