Xamarin为精灵动画形成ImageSource?

101*_*ris 1 xamarin xamarin.forms

我想在我的Xamarin表格上放一点动画徽标.

它基本上有效,但看起来很糟糕.IE闪烁

它似乎是ImageSource.FromFile()是懒惰的,每次访问时都从存储器加载文件,或者设置Image.Source没有缓冲并导致撕裂/闪烁,或两者兼而有之?

我是xamarin的新手,我以前从未在本机java/obj-c中使用过这个问题.

有没有人有什么建议?有没有办法强制ImageSource实际预先加载到内存中?有没有办法更新Image.Source属性没有闪烁?或者我应该尝试转移到XamarinIOS/Android自定义(本机)控件?

 public partial class SplashIntro : ContentPage {

    ImageSource[] sprites = new ImageSource[17];

    public SplashIntro() {
      InitializeComponent();
      LoadSplashImages();
      this.Appearing += SplashIntro_Appearing;
    }

    private void SplashIntro_Appearing(object sender, EventArgs e) {
      PlayAni();
    }

    void LoadSplashImages() {
      for (int i = 0; i < sprites.Length; i++) {
        ImageSource ims = ImageSource.FromFile($"logani{i + 1}.png");
        sprites[i] = ims;
      }
    }

    void PlayAni() {
      aniImage.Source = sprites[0];
      int nextFrame = 1;
      Device.StartTimer(TimeSpan.FromMilliseconds(80), () => {
        //  Device.BeginInvokeOnMainThread(() => { aniImage.Source = sprites[nextFrame]; });
        aniImage.Source = sprites[nextFrame];
        nextFrame++;
        if (nextFrame == sprites.Length) nextFrame = 0;
        return true;
      });
    }
  }
Run Code Online (Sandbox Code Playgroud)

Sus*_*ver 6

通过自定义渲染器执行此操作将是了解每个平台功能的最佳方法:

iOS:这可以通过将UIImages 数组应用于UIImageView.AnimationImage属性来完成.

Android:一种方法,就是将"动画列表"设置为可绘制的背景ImageView.

在此输入图像描述

(gif很奇怪,但这两种技术在设备上运行顺畅(大多数模拟器;-)

注意:此示例代码使用10个图像(frame_X.png),这些图像链接在iOS 资源和Android 资源/ drawable下.

Xamarin.Forms具有Image可绑定Animate属性的自定义控件:

public class AnimatedImage : Image
{
    public static readonly BindableProperty AnimateProperty = BindableProperty.Create(
        propertyName: "Animate",
        returnType: typeof(bool),
        declaringType: typeof(AnimatedImage),
        defaultValue: false);

    public bool Animate
    {
        get { return (bool)GetValue(AnimateProperty); }
        set { SetValue(AnimateProperty, value); }
    }
}
Run Code Online (Sandbox Code Playgroud)

iOS自定义ImageRenderer:

[assembly: ExportRenderer(typeof(AnimatedImage), typeof(AnimatedImageRenderer_iOS))]
namespace AnimImage.iOS
{
    public class AnimatedImageRenderer_iOS : ImageRenderer
    {
        const int imageCount = 10;
        NSMutableArray imageArray;
        public AnimatedImageRenderer_iOS() {
            imageArray = new NSMutableArray(imageCount);
            for (int i = 0; i < imageCount; i++)
                imageArray.Add(UIImage.FromFile(new NSString($"frame_{i}.png")));
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
        {
            base.OnElementChanged(e);
            if (Control != null)
            {
                Control.AnimationImages = NSArray.FromArray<UIImage>(imageArray);
                Control.AnimationDuration = 1;
                Control.AnimationRepeatCount = 0;
                if (e.NewElement != null)
                {
                    if ((e.NewElement as AnimatedImage).Animate)
                        Control.StartAnimating();
                }
            }
        }
        protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if (e.PropertyName == "Animate")
            {
                if ((sender as AnimatedImage).Animate)
                    Control?.StartAnimating();
                else
                    Control?.StopAnimating();
            }
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

Android自定义ImageRenderer:

[assembly: ExportRenderer(typeof(AnimatedImage), typeof(AnimatedImageRenderer_Droid))]
namespace AnimImage.Droid
{
    public class AnimatedImageRenderer_Droid : ImageRenderer
    {
        public AnimatedImageRenderer_Droid() { }

        AnimationDrawable anim;
        protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
        {
            base.OnElementChanged(e);
            if (Control != null)
            {
                Control.SetBackgroundResource(Resource.Drawable.animatedlogo);
                if (e.NewElement != null)
                {
                    if ((e.NewElement as AnimatedImage).Animate)
                    {
                        (Control.Background as AnimationDrawable)?.Start();
                        Control.ImageAlpha = 0;
                    }
                }
            }
        }
        protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if (e.PropertyName == "Animate")
            {
                if ((sender as AnimatedImage).Animate)
                {
                    (Control.Background as AnimationDrawable)?.Start();
                    Control.ImageAlpha = 0;
                }
                else
                {
                    Control.ImageAlpha = 255;
                    (Control.Background as AnimationDrawable)?.Stop();
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Android animation-listDrawable:

<?xml version="1.0" encoding="UTF-8" ?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/frame_0" android:duration="100" />
    <item android:drawable="@drawable/frame_1" android:duration="100" />
    <item android:drawable="@drawable/frame_2" android:duration="100" />
    <item android:drawable="@drawable/frame_3" android:duration="100" />
    <item android:drawable="@drawable/frame_4" android:duration="100" />
    <item android:drawable="@drawable/frame_5" android:duration="100" />
    <item android:drawable="@drawable/frame_6" android:duration="100" />
    <item android:drawable="@drawable/frame_7" android:duration="100" />
    <item android:drawable="@drawable/frame_8" android:duration="100" />
    <item android:drawable="@drawable/frame_9" android:duration="100" />
</animation-list>
Run Code Online (Sandbox Code Playgroud)