Xamarin.Forms:在数据加载期间IsBusy为true时,如何至少显示一次Lottie动画?

问题描述

在我的 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();
    }
}

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