效果如何找出它所附加的 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
改变时,UIImageView
(Bounds
或 Frame
)有一个尺寸。但是,如果在 XAML 中静态设置源,则该逻辑不会 运行:因此对 ApplyGlow
的唯一调用是在 OnAttach
期间。不幸的是,在 OnAttach
期间,UIImageView
的大小为 (0, 0)
。
如何使用静态 Source
在 iOS 上实现此效果?
注意:等效的 Android 效果通过附加到 ImageView.ViewTreeObserver.PreDraw
的处理程序起作用 - 此时大小是已知的。因此,如果存在 iOS 等效事件,那将是一种解决方法。
更多详情:
原始实现使用原始图像大小 (imageView.Image.Size) - 在 OnAttach
期间可用。这可以达到 "work",但并不令人满意:发光应用于全尺寸图像。如果图像明显大于视图区域,发光的半径会变得太小(iOS 在渲染时缩小图像+发光):它没有所需的外观。
ApplyGlow
有一个选项可以为图像应用色调。该色调颜色不同于发光颜色。我提到这个是因为它限制了可能的解决方案:AFAIK,不能只在图像上设置选项并让 iOS 弄清楚如何渲染它 - 需要明确调整图像大小并在其上绘制调整大小的着色图像模糊版本(发光)。此代码全部有效 - if 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);
}
在 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
改变时,UIImageView
(Bounds
或 Frame
)有一个尺寸。但是,如果在 XAML 中静态设置源,则该逻辑不会 运行:因此对 ApplyGlow
的唯一调用是在 OnAttach
期间。不幸的是,在 OnAttach
期间,UIImageView
的大小为 (0, 0)
。
如何使用静态 Source
在 iOS 上实现此效果?
注意:等效的 Android 效果通过附加到 ImageView.ViewTreeObserver.PreDraw
的处理程序起作用 - 此时大小是已知的。因此,如果存在 iOS 等效事件,那将是一种解决方法。
更多详情:
原始实现使用原始图像大小 (imageView.Image.Size) - 在
OnAttach
期间可用。这可以达到 "work",但并不令人满意:发光应用于全尺寸图像。如果图像明显大于视图区域,发光的半径会变得太小(iOS 在渲染时缩小图像+发光):它没有所需的外观。ApplyGlow
有一个选项可以为图像应用色调。该色调颜色不同于发光颜色。我提到这个是因为它限制了可能的解决方案:AFAIK,不能只在图像上设置选项并让 iOS 弄清楚如何渲染它 - 需要明确调整图像大小并在其上绘制调整大小的着色图像模糊版本(发光)。此代码全部有效 - ifimageView.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);
}