在数据加载期间 IsBusy 为真时,如何至少显示一次 Lottie 动画?
How do I display a Lottie animation at least one time when IsBusy is true during data loading?
在我的 Xamarin.Forms 项目 上,我想在 [=] 期间显示一个 Lottie 动画 37=] 调用 或在 加载网站 期间 WebView
.
为此,我将 Lottie 动画 的 IsVisible
属性 绑定到 IsBusy
属性我的 ViewModels:效果很好。
<lottie:AnimationView Animation="resource://lottie_loading.json?assembly=MyApp"
AnimationSource="EmbeddedResource"
BackgroundColor="Transparent"
AutoPlay="True"
RepeatMode="Infinite"
IsVisible="{Binding IsBusy}">
但是加载时间有时很短,所以我想找到一种方法在隐藏它之前完全显示一次 Lottie 动画。
可能吗?实现此目标的更好方法是什么?
I would like to display a Lottie animation during API calls
public async void loadData()
{
//Data load started
viewModel.IsBusy = true;
await methodOfLoadingData...;
//Data load finished
viewModel.IsBusy = false;
}
during the loading of a website in a WebView:
private void MyWebView_Navigating(object sender, WebNavigatingEventArgs e)
{
viewModel.IsBusy = true;
}
private void MyWebView_Navigated(object sender, WebNavigatedEventArgs e)
{
viewModel.IsBusy = false;
}
But the loading duration is sometimes very short
加载持续时间取决于您完全加载 data/webview 的时间。如果你加载 data/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 中,我声明了一个与 IsBusy
和命令 [=21] 相关的 属性 ShowAnimation
=] 像这样:
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 以防出现问题(超时,无法访问服务器,...)和一个 Reload/Retry 按钮,我不得不添加一些代码:
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
// for display loading animation on Refresh
while (ShowLoadingView)
await Task.Delay(50);
SetServiceError();
}
在 Loader 与 Data loading 相关的情况下,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()
。我还没有调查,但我已经通过在 OnFinishedAnimation()
:
中添加对 SetServiceError()
的调用来解决这个问题
private async Task OnFinishedAnimation(object sender)
{
var view = sender as AnimationView;
if (IsBusy)
{
view.PlayAnimation();
}
else
{
ShowLoadingView = false;
// fix SetServiceError() call issue
await SetServiceError();
}
}
不要犹豫,说出可以做些什么来优化它。
在我的 Xamarin.Forms 项目 上,我想在 [=] 期间显示一个 Lottie 动画 37=] 调用 或在 加载网站 期间 WebView
.
为此,我将 Lottie 动画 的 IsVisible
属性 绑定到 IsBusy
属性我的 ViewModels:效果很好。
<lottie:AnimationView Animation="resource://lottie_loading.json?assembly=MyApp"
AnimationSource="EmbeddedResource"
BackgroundColor="Transparent"
AutoPlay="True"
RepeatMode="Infinite"
IsVisible="{Binding IsBusy}">
但是加载时间有时很短,所以我想找到一种方法在隐藏它之前完全显示一次 Lottie 动画。
可能吗?实现此目标的更好方法是什么?
I would like to display a Lottie animation during API calls
public async void loadData()
{
//Data load started
viewModel.IsBusy = true;
await methodOfLoadingData...;
//Data load finished
viewModel.IsBusy = false;
}
during the loading of a website in a WebView:
private void MyWebView_Navigating(object sender, WebNavigatingEventArgs e)
{
viewModel.IsBusy = true;
}
private void MyWebView_Navigated(object sender, WebNavigatedEventArgs e)
{
viewModel.IsBusy = false;
}
But the loading duration is sometimes very short
加载持续时间取决于您完全加载 data/webview 的时间。如果你加载 data/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 中,我声明了一个与 IsBusy
和命令 [=21] 相关的 属性 ShowAnimation
=] 像这样:
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 以防出现问题(超时,无法访问服务器,...)和一个 Reload/Retry 按钮,我不得不添加一些代码:
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
// for display loading animation on Refresh
while (ShowLoadingView)
await Task.Delay(50);
SetServiceError();
}
在 Loader 与 Data loading 相关的情况下,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()
。我还没有调查,但我已经通过在 OnFinishedAnimation()
:
SetServiceError()
的调用来解决这个问题
private async Task OnFinishedAnimation(object sender)
{
var view = sender as AnimationView;
if (IsBusy)
{
view.PlayAnimation();
}
else
{
ShowLoadingView = false;
// fix SetServiceError() call issue
await SetServiceError();
}
}
不要犹豫,说出可以做些什么来优化它。