在Xamarin.Forms中,Effect
可以附加到View
。就我而言,视图显示Image
。效果是在图像的可见像素周围产生彩色"发光"。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
更改时,UIImageView
(Bounds
或Frame
(具有大小。但是,如果在 XAML 中静态设置源,则该逻辑不会运行:因此对ApplyGlow
的唯一调用是在OnAttach
期间。不幸的是,在OnAttach
期间,UIImageView
的大小(0, 0)
。
如何让这种效果在 iOS 上使用静态Source
?
注意:等效的 Android 效果通过附加到ImageView.ViewTreeObserver.PreDraw
的处理程序工作 - 此时大小已知。因此,如果存在iOS等效事件,那将是一种解决方法。
更多详情:
原始实现使用原始图像大小(imageView.Image.Size( - 在
OnAttach
期间可用。这可以"工作",但并不令人满意:发光应用于全尺寸图像。如果图像明显大于视图区域,则发光的半径会变得太小(iOS 在渲染时缩小图像+发光(:它没有所需的外观。ApplyGlow
可以选择将色调应用于图像。该色调与发光颜色不同。我提到这一点是因为它限制了可能的解决方案:AFAIK,不能只在图像上设置选项并让 iOS 弄清楚如何渲染它 - 需要显式调整图像大小并在模糊版本(发光(上绘制调整大小的有色图像。这段代码都有效 -如果imageView.Bounds.Size
(或imageView.Frame.Size
(可用(且非零(。使用
OnElementPropertyChanged
中的断点,我已经检查了 imageView 大小是否已知对于始终设置的任何属性。不;如果未动态设置任何属性,则属性更改全部发生在 imageView 具有大小之前。
也许这是一种解决方法,我不知道您是否可以接受。
在OnAttached
中呼叫ApplyGlow();
之前添加一点延迟。延迟后,您将获得imageView.Frame.Size
或imageView.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);
}