在数据加载期间 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;
}

如果 LoaderWebView 相关,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();
}

LoaderData 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();
    }
}

不要犹豫,说出可以做些什么来优化它。