Closed pcdus closed 3 years ago
Can you make a PR to fix this?
I can take a look, but I already have an error when I try to build the sources project.
For the moment, I found another solution by using OnFinishedAnimation
, even if this solution is a bit heavy and can be improved.
Firstly, as recommended there, I've created 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();
}
}
I also used EventToCommandBehaviors
, like described there.
After this I can use the Lottie animation like this:
<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>
And in my ViewModel, I've declared a property ShowAnimation
that is related to IsBusy
and the Command OnFinishedAnimationCommand
like this:
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;
}
In case of the Loader is related to a WebView
, the ShowLoadingView
property is set like this:
private Task WebViewNavigatingAsync(WebNavigatingEventArgs eventArgs)
{
IsBusy = true;
ShowLoadingView = true;
return Task.CompletedTask;
}
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
}
But, as I also display an ErrorView in case of issues (timeout, unreachable server, ...) and a Reload/Retry button, I had to add some code:
private async Task WebViewNavigatedAsync(WebNavigatedEventArgs eventArgs)
{
IsBusy = false;
// for display loading animation on Refresh
while (ShowLoadingView)
await Task.Delay(50);
SetServiceError();
}
In case of the Loader is related to Data loading, the ShowLoadingView
property is set like this:
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();
}
}
However, I noticed that in some cases the SetServiceError()
was not fired, as OnFinishedAnimation()
was called in the same time. I haven't yet investigated, but I've fixed this by adding the call to SetServiceError()
in in 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();
}
}
This works as expected, but it could be simplified by using other events...
OnRepeatAnimation works. OnAnimationUpdate is not available on iOS because the native platform does not expose it.
🚀 Feature Requests
During some tests, I've seen that the events
OnAnimationUpdate
andOnRepeatAnimation
are only fired on Android.Contextualize the feature
When we want to use the Lottie animation as Loading animation in Xamarin.Forms, these events could help to manage the animation display.
By default, we can use:
But in some cases, the loading is too quick so the animation is only visible during a short time, which is not a great user experience.
To optimize this, we could display the animation least once fully, or to always play the animation fully before to hide it.
For this, we can use
OnFinishedAnimation
event and create another property likeShowAnimation
that will be set during data loading.For example:
The Lottie animation will now be bind to this property, without the infinite
RepeatMode
:And through
EventToCommandBehavior
we will be able to access to theOnFinishedAnimation
event in the ViewModel:This works well, but there is then another issue: if we reload the data through "Retry" button after an error, or through a "Refresh" icon toolbar, the Lottie animation is not relaunched automatically.
Describe the feature
To fix this, we could use the events
OnAnimationUpdate
andOnRepeatAnimation
: but they are not fired on iOS.Platforms affected (mark all that apply)