问题描述
在我的 Xamarin.Forms项目中,我想在 API调用期间或在网站中的 WebView
中.
On my Xamarin.Forms project, I would like to display a Lottie animation during API calls or during the loading of a website in a WebView
.
为此,我将 Lottie动画的 IsVisible
属性绑定到了 ViewModels IsBusy 属性:效果很好.
For this, I've bounded the IsVisible
property of the Lottie animation to the IsBusy
property of my ViewModels: this works well.
<lottie:AnimationView Animation="resource://lottie_loading.json?assembly=MyApp"
AnimationSource="EmbeddedResource"
BackgroundColor="Transparent"
AutoPlay="True"
RepeatMode="Infinite"
IsVisible="{Binding IsBusy}">
但是加载时间有时很短,因此我想找到一种方法来完全显示一次Lottie动画,然后将其隐藏.
But the loading duration is sometimes very short, so I would like to found a way to display the Lottie animation once in full before to hidden it.
=>是否可以?有什么更好的方法来实现这一目标?
推荐答案
我发现了另一种可行的方法,即使该解决方案有点繁琐并且可以改进.
I've found another approach that works, even if this solution is a bit heavy and can be improved.
Firstly, as recommended there, I've created 2 Triggers
:
public class PlayLottieAnimationTriggerAction : TriggerAction<AnimationView>
{
protected override void Invoke(AnimationView sender)
{
Debug.WriteLine($"PlayLottieAnimationTriggerAction()");
sender.PlayAnimation();
}
}
public class StopLottieAnimationTriggerAction : TriggerAction<AnimationView>
{
protected override void Invoke(AnimationView sender)
{
Debug.WriteLine($"StopLottieAnimationTriggerAction()");
sender.StopAnimation();
}
}
我还使用了 EventToCommandBehaviors
,如有.
在此之后,我可以像这样使用 Lottie动画:
After this I can use the Lottie animation like this:
<forms:AnimationView
x:Name="animationView"
BackgroundColor="Transparent"
AutoPlay="True"
IsVisible="{Binding ShowAnimation}"
Animation="resource://lottie_4squares_apricot_blond.json?assembly=Example.Forms"
AnimationSource="EmbeddedResource"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<forms:AnimationView.Triggers>
<MultiTrigger TargetType="forms:AnimationView">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding ShowAnimation}" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.EnterActions>
<triggers:LottieTriggerAction />
</MultiTrigger.EnterActions>
<MultiTrigger.ExitActions>
<actions:StopLottieAnimationTriggerAction />
</MultiTrigger.ExitActions>
</MultiTrigger>
</forms:AnimationView.Triggers>
<forms:AnimationView.Behaviors>
<behaviors:EventToCommandBehavior
EventName="OnFinishedAnimation"
Command="{Binding OnFinishedAnimationCommand}"
CommandParameter="{x:Reference animationView}"/>
</forms:AnimationView.Behaviors>
</forms:AnimationView>
在我的 ViewModel 中,我声明了一个属性 ShowAnimation
,该属性与 IsBusy
和命令 OnFinishedAnimationCommand 像这样的代码:
And in my ViewModel, I've declared a property ShowAnimation
that is related to IsBusy
and the Command OnFinishedAnimationCommand
like this:
private bool _showAnimation;
public bool ShowAnimation
{
get => _showAnimation;
set => Set(ref _showAnimation, value);
}
public ICommand OnFinishedAnimationCommand
{
get
{
return new Xamarin.Forms.Command<object>(async (object sender) =>
{
if (sender != null)
{
await OnFinishedAnimation(sender);
}
});
}
}
private Task OnFinishedAnimation(object sender)
{
var view = sender as AnimationView;
if (IsBusy)
{
view.PlayAnimation();
}
else
{
ShowAnimation = false;
}
return Task.CompletedTask;
}
如果 Loader 与 WebView
相关,则 ShowLoadingView
属性设置如下:
In case of the Loader is related to a WebView
, the ShowLoadingView
property is set like this:
private Task WebViewNavigatingAsync(WebNavigatingEventArgs eventArgs)
{
IsBusy = true;
ShowLoadingView = true;
return Task.CompletedTask;
}
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
}
但是,由于在出现问题(超时,服务器无法访问,...)和重新加载/重试"按钮的情况下,我还显示了 ErrorView ,因此我不得不添加一些代码:
But, as I also display an ErrorView in case of issues (timeout, unreachable server, ...) and a Reload/Retry button, I had to add some code:
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
// for display loading animation on Refresh
while (ShowLoadingView)
await Task.Delay(50);
SetServiceError();
}
如果Loader与数据加载相关,ShowLoadingView
属性设置如下:
In case of the Loader is related to Data loading, the ShowLoadingView
property is set like this:
private async Task GetNewsAsync(bool forceRefresh = false)
{
try
{
ShowErrorView = false;
ErrorKind = ServiceErrorKind.None;
IsBusy = true;
ShowLoadingView = true;
var _news = await _dataService.GetNews(forceRefresh);
News = new ObservableCollection<News>(_news);
}
catch (Exception ex)
{
ErrorKind = ServiceErrorKind.ServiceIssue;
}
finally
{
IsBusy = false;
await SetServiceError();
}
}
然而,我注意到在某些情况下 SetServiceError()
没有被触发,因为 OnFinishedAnimation()
被同时调用.我尚未进行调查,但已通过在 OnFinishedAnimation()
中将调用添加到 SetServiceError()
中来解决此问题:
However, I noticed that in some cases the SetServiceError()
was not fired, as OnFinishedAnimation()
was called in the same time. I haven't yet investigated, but I've fixed this by adding the call to SetServiceError()
in in OnFinishedAnimation()
:
private async Task OnFinishedAnimation(object sender)
{
var view = sender as AnimationView;
if (IsBusy)
{
view.PlayAnimation();
}
else
{
ShowLoadingView = false;
// fix SetServiceError() call issue
await SetServiceError();
}
}
不要犹豫,说出可以做些什么来优化这一点.
Don't hesitate to tell what could be done to optimize this.
这篇关于Xamarin.Forms:如何在数据加载期间 IsBusy 为真时至少显示一次 Lottie 动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!