【问题标题】:How do I display a Lottie animation at least one time when IsBusy is true during data loading?在数据加载期间 IsBusy 为 true 时,如何至少显示一次 Lottie 动画?
【发布时间】:2021-02-18 13:36:39
【问题描述】:

在我的 Xamarin.Forms 项目中,我想在 API 调用加载WebView 中的网站

为此,我已将 Lottie 动画IsVisible 属性绑定到我的 ViewModelsIsBusy 属性:效果很好。

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

但是加载时间有时很短,所以我想找到一种方法,在完全显示 Lottie 动画之前将其隐藏

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

【问题讨论】:

  • Task.Delay 可以帮忙吗?比如你的数据加载方法中的await Task.Delay(500).ConfigureAwait(false);
  • 也许可以,但这并不完美,我无法为 WebView 执行此操作。
  • 在更新 IsBusy 的值之前将延迟添加到“OnNavigated”中。另外,这并不完美,因为加载时间会有所不同,您必须在完整动画和实际加载时间之间找到平衡。
  • 我的解决方案对您有用吗?如果是,请您接受(点击此答案左上角的☑️),以便我们帮助更多有同样问题的人:)。您也可以标记自己的解决方案:)。

标签: xamarin xamarin.forms mvvm loading lottie


【解决方案1】:

我想在 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 的时间。如果你加载数据/webview 非常快,加载时间应该很短。

【讨论】:

    【解决方案2】:

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

    首先,按照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 相关的属性 ShowAnimation 和命令 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;
    }
    

    如果 LoaderWebView 相关,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() 被同时调用。我还没有调查,但我已经通过在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();
        }
    }
    

    不要犹豫,告诉我们可以做些什么来优化它。

    【讨论】:

      猜你喜欢
      • 2020-01-25
      • 2010-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多