首页 > 解决方案 > 使用 MvvmCross 和 FFImageLoading 的 Xamarin Android 可见性绑定问题

问题描述

为了在我的应用程序(使用 Mvx 和 FFimageLoading 的 Xamarin AndroidX)中​​创建动画加载程序 UI 控件,我创建了一个继承自MvxCachedImageView. 然后我应用我的动画如下:

public class LoaderView : MvxCachedImageView
    {
        protected LoaderView(IntPtr javaReference, JniHandleOwnership transfer)
            : base(javaReference, transfer)
        {
            Create();
        }

        public LoaderView(Context context)
            : base(context)
        {
            Create();
        }

        public LoaderView(Context context, IAttributeSet attrs)
            : base(context, attrs)
        {
            Create();
        }

        private void Create()
        {
            if (Context == null)
                return;

            ImageService.Instance.LoadCompiledResource("loader_indicator")
                .Into(this);

            ApplyRotation();

            StartAnimation(Animation);
        }
        
        private void ApplyRotation()
        {
            var rotation = new RotateAnimation(
                0,
                360,
                Dimension.RelativeToSelf,
                0.5f,
                Dimension.RelativeToSelf,
                0.5f)
            {
                Duration = 1200,
                Interpolator = new DecelerateInterpolator(1.25f),
                RepeatCount = Animation.Infinite
            };

            Animation = rotation;
        }
    }

注意loader_indicator是一个gif文件

在我尝试将其可见性属性绑定到“经典”BaseViewModel 的属性之前,此控件一直正常工作IsLoading,如下所示:

var set = CreateBindingSet();
set.Bind(loader).For(v => v.Visibility).To(vm => vm.IsLoading)
                .WithConversion<MvxVisibilityValueConverter>();
set.Apply();

如上所述执行应用程序,Visibility 绑定和 gif 动画随机工作:有时会,有时不会;有时,RotateAnimation它正在工作,但针对父元素而不是本身 - 在糟糕的情况下,您的图标会进入页面..

做不同的测试我已经明白,如果我删除ApplyRotation并且StartAnimation控件会binded正确显示。

这似乎是某个地方的线程问题。有没有人见过并(可能)解决了这个问题?

编辑: Cheesebaron anwser 给了我一个正确的提示,所以我改变了LoaderView实现如下,它实际上解决了这个问题:

public class LoaderView : MvxCachedImageView
{
    private Animation _animation;

    protected LoaderView(IntPtr javaReference, JniHandleOwnership transfer)
        : base(javaReference, transfer)
    { }

    public LoaderView(Context context)
        : base(context)
    { }

    public LoaderView(Context context, IAttributeSet attrs)
        : base(context, attrs)
    { }

    protected override void OnVisibilityChanged(View changedView, ViewStates visibility)
    {
        base.OnVisibilityChanged(changedView, visibility);

        if (visibility == ViewStates.Visible)
            StartAnimation(_animation);
        else
            ClearAnimation();
    }

    protected override void OnAttachedToWindow()
    {
        base.OnAttachedToWindow();
        Create();
    }

    private void Create()
    {
        if (Context == null)
            return;

        ImageService.Instance.LoadCompiledResource("loader_indicator")
            .Into(this);

        _animation = ApplyRotation();
    }

    private static RotateAnimation ApplyRotation() =>
        new RotateAnimation(
            0,
            360,
            Dimension.RelativeToSelf,
            0.5f,
            Dimension.RelativeToSelf,
            0.5f)
        {
            Duration = 1200,
            Interpolator = new DecelerateInterpolator(1.25f),
            RepeatCount = Animation.Infinite
        };

}

标签: androidxamarinmvvmcrossffimageloading

解决方案


您可以尝试将绑定表达式更改为:

set.Bind(loader).For(v => v.BindVisible()).To(vm => vm.IsLoading);

但是,您是在实例化元素时应用动画,而不是在设置可见性时应用动画。因此动画可能正在运行,而元素不可见或反之亦然。您可能希望在更合适的时间点开始动画。


推荐阅读