问题描述
在我的 Xamarin.Forms项目中,我想在 API调用期间或在加载以下内容时显示 Lottie动画 G<-function(i,x,n,Sum,IE,PE,CE,PP,FT,IB,IP)
{
if (IB==1)
{
if(PP==1)
{G=12}
else
{G=13}
}
if (IB==2)
{
if (PP==1)
{G=1}
else {G=2}
}
return(G)
}
中的一个网站。
为此,我将 Lottie动画的WebView
属性限制为我的 viewmodels 的IsVisible
属性:
IsBusy
但是加载时间有时很短,因此我想找到一种方法来完全显示一次Lottie动画,然后将其隐藏。
=>可以吗?有什么更好的方法来实现这一目标?
解决方法
我想在 API调用
期间显示Lottie动画
public async void loadData()
{
//Data load started
viewModel.IsBusy = true;
await methodOfLoadingData...;
//Data load finished
viewModel.IsBusy = false;
}
在WebView中加载网站期间:
private void MyWebView_Navigating(object sender,WebNavigatingEventArgs e)
{
viewModel.IsBusy = true;
}
private void MyWebView_Navigated(object sender,WebNavigatedEventArgs e)
{
viewModel.IsBusy = false;
}
但是加载时间有时很短
加载时间取决于完全加载数据/ webview的时间。如果您非常快速地加载数据/网络视图,则加载时间应较短。
,我发现了另一种可行的方法,即使该解决方案有点繁琐并且可以改进。
首先,按照推荐的there,我创建了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
,就像there所述。
此后,我可以像这样使用 Lottie动画:
<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
和Command IsBusy
相关的属性OnFinishedAnimationCommand
,如下所示:
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
属性设置如下:
private Task WebViewNavigatingAsync(WebNavigatingEventArgs eventArgs)
{
IsBusy = true;
ShowLoadingView = true;
return Task.CompletedTask;
}
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
}
但是,由于在出现问题(超时,服务器无法访问,...)和“重新加载/重试”按钮的情况下,我还显示了 ErrorView ,所以我不得不添加一些代码:
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
// for display loading animation on Refresh
while (ShowLoadingView)
await Task.Delay(50);
SetServiceError();
}
如果 Loader 与数据加载相关,则ShowLoadingView
属性设置如下:
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()
是同时被调用的。我尚未进行调查,但已通过在SetServiceError()
中的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();
}
}
不要犹豫,说出可以做些什么来优化这一点。