Xamarin.forms 表单:在数据加载期间,当IsBusy为true时,如何至少显示一次乐透动画?

Xamarin.forms 表单:在数据加载期间,当IsBusy为true时,如何至少显示一次乐透动画?,xamarin.forms,mvvm,loading,lottie,lottie-xamarin,Xamarin.forms,Mvvm,Loading,Lottie,Lottie Xamarin,在我的Xamarin.Forms项目中,我想在API调用期间或在WebView中加载网站期间显示乐蒂动画 为此,我将乐蒂动画的IsVisible属性限定为我的视图模型的IsBusy属性:这很有效 <lottie:AnimationView Animation="resource://lottie_loading.json?assembly=MyApp" AnimationSource="EmbeddedResource"

在我的Xamarin.Forms项目中,我想在API调用期间或在
WebView
中加载网站期间显示乐蒂动画

为此,我将乐蒂动画的
IsVisible
属性限定为我的视图模型的
IsBusy
属性:这很有效

<lottie:AnimationView Animation="resource://lottie_loading.json?assembly=MyApp"
        AnimationSource="EmbeddedResource"
        BackgroundColor="Transparent"
        AutoPlay="True"
        RepeatMode="Infinite"
        IsVisible="{Binding IsBusy}">

但是加载持续时间有时非常短,因此我想找到一种方法,在隐藏乐蒂动画之前,完整地显示乐蒂动画

=>可能吗?实现这一目标的更好方法是什么?

我想在API调用期间显示乐透动画

在Web视图中加载网站期间:

但装载时间有时很短


加载持续时间取决于完全加载数据/webview的时间。如果您很快加载数据/webview,加载持续时间应该很短。

我找到了另一种可行的方法,即使这个解决方案有点繁重并且可以改进

首先,根据建议,我创建了2个
触发器

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();
    }
}
在我的ViewModel中,我声明了一个属性
ShowAnimation
,它与
IsBusy
和命令
onfinishedanimation
相关,如下所示:

<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>
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;
}
private Task WebViewNavigatingAsync(WebNavigatingEventArgs eventArgs)
{
    IsBusy = true;
    ShowLoadingView = true;
    return Task.CompletedTask;
}

private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
    IsBusy = false;
}
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();
    }
但是,由于在出现问题(超时、无法访问服务器等)时,我还显示了一个错误视图和一个重新加载/重试按钮,因此我必须添加一些代码:

private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
    IsBusy = false;
    // for display loading animation on Refresh
    while (ShowLoadingView)
        await Task.Delay(50);
    SetServiceError();
}
如果加载程序与数据加载相关,则
ShowLoadingView
属性设置如下:

<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>
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;
}
private Task WebViewNavigatingAsync(WebNavigatingEventArgs eventArgs)
{
    IsBusy = true;
    ShowLoadingView = true;
    return Task.CompletedTask;
}

private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
    IsBusy = false;
}
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();
    }

请毫不犹豫地告诉我们可以做些什么来优化它。

是否有帮助?比如
等待任务。延迟(500)。配置等待(false)
在数据加载方法中可能是这样,但这并不完美,我无法对WebView执行此操作。在更新IsBusy的值之前,将延迟添加到“OnNavigated”中。另外,随着加载时间的变化,这并不完美,您必须在全长动画和真实加载时间之间找到平衡。我的解决方案对您有效吗?如果是,请您接受(单击☑️ 在这个答案的左上角),这样我们就可以帮助更多有同样问题的人:)。您还可以标记自己的解决方案:)。