Xamarin Android 使用 MvvmCross 和 FFImageLoading 的可见性绑定问题
Xamarin Android visibility binding issue using MvvmCross and FFImageLoading
为了在我的应用程序(使用 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文件
此控件一直正常工作,直到我尝试将其可见性 属性 绑定到 'classic' IsLoading
BaseViewModel 的 属性,如下所示:
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
};
}
您可以尝试将绑定表达式更改为:
set.Bind(loader).For(v => v.BindVisible()).To(vm => vm.IsLoading);
但是,您是在实例化元素时应用动画,而不是在设置可见性时应用动画。所以动画可能是 运行,而元素是不可见的,反之亦然。您可能希望在更合适的时间点开始播放动画。
为了在我的应用程序(使用 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文件
此控件一直正常工作,直到我尝试将其可见性 属性 绑定到 'classic' IsLoading
BaseViewModel 的 属性,如下所示:
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
};
}
您可以尝试将绑定表达式更改为:
set.Bind(loader).For(v => v.BindVisible()).To(vm => vm.IsLoading);
但是,您是在实例化元素时应用动画,而不是在设置可见性时应用动画。所以动画可能是 运行,而元素是不可见的,反之亦然。您可能希望在更合适的时间点开始播放动画。