The current Animation
implementation seems complex and performs poorly when multiple non-trivial views are animated (such as translating two ListViews at the same time). There should be a new way for us to animate objects by taking advantage of hardware acceleration and avoiding things like a timer.
I can't find a good substitute for the current implementation. I've looked at Xamarin Transitions, but the project is not actively being maintained and doesn't seem to work as of now.
Would #4233 help with that?
It's not clear to me if Storyboard
is building on top of the existing animation implementation. It sounds like that's the case. If it is true, then Storyboard
will have the same issues. We need to be able to leverage hardware acceleration (see this post) and use native animation APIs as much as possible. The current implementation was written back in 2012 and needs to be re-thought, imo.
I would say it should apply to all form navigation so it will look like this:
Navigation.PushModalAsync(new NavigationPage(new MyForm()), Transition.SlideFromTop, 2000);
Where 2000 is the time to take in milliseconds
The Transition can be:
The same thing can e applied to OnDisappearing,
for example below I am opening the page using SlideFromLeft:
Navigation.PushModalAsync(new NavigationPage(new MyForm()), Transition.SlideFromLeft(2000));
and closing it using Fade:
protected override void OnDisappearing()
{
base.OnDisappearing();
Transition.Fade(2000);
}
Thanks,
Jassim
@jrahma I believe there is an existing issue / PR for what you need. This issue is different in that I want a better animation framework that hands off as much work as possible to the native layers to do basic translate, scale, fade, etc. So, when I do something like:
await Task.WhenAll
(
view1.TranslateTo (-100, 0),
view2.TranslateTo (0, 0)
);
this animation should be smooth when view1
and view2
are complex instead of simple box views or buttons.
I've recently created a simple, hacky dependency service that animates views for me. The animations are 10x better compared to using Xamarin Forms' animation framework. I directly use ObjectAnimator
on Android and UIViewPropertyAnimator
on iOS. It does the job for me for my use case, but it skips a lot of visual element tracking Forms does, so it's not for production use. :)
@adrianknight89 would you care to share your hacky solution?
@raindeer I'll get back to you on this later. I'm a bit busy right now with work and other things. I hope to update you back this weekend.
@raindeer Hi, sorry I forgot about this...
Here's the Android implementation (assuming TranslateViewAsync(View view)
is set up as a dependency service method):
public async Task TranslateViewAsync(View view)
{
var renderer = view.GetRenderer();
renderer.View.SetLayerType(LayerType.Hardware, null);
ObjectAnimator objectAnimator;
objectAnimator = ObjectAnimator.OfFloat(renderer.View, "translationX", 0);
objectAnimator.SetInterpolator(new DecelerateInterpolator());
var animatorSet = new AnimatorSet();
var animators = new List<Animator> { objectAnimator };
animatorSet.SetDuration(300);
animatorSet.PlayTogether(animators);
animatorSet.AnimationEnd += (sender, args) =>
{
renderer.View.SetLayerType(LayerType.None, null);
view.TranslationX = 0;
};
await animatorSet.StartAsync();
}
public static class AnimatorExtensions
{
public static Task StartAsync(this Animator animator)
{
var taskAnimationListener = new TaskAnimationListener();
animator.AddListener(taskAnimationListener);
animator.Start();
return taskAnimationListener.Task;
}
}
This one translates the view on the x axis to point 0. For other properties, you'll need to swap the corresponding Android property names. Make sure to notify Forms of the final change in the AnimationEnd
event.
iOS is a bit tricky. I'm sure there is a better way to do this.
public async Task TranslateViewAsync(View view)
{
var finished = false;
CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() =>
{
var renderer = Platform.GetRenderer(view);
renderer.NativeView.Transform = CGAffineTransform.MakeTranslation(375, 0);
var uiViewPropertyAnimator = new UIViewPropertyAnimator(0.3, UIViewAnimationCurve.EaseOut, () =>
{
renderer.NativeView.Transform = CGAffineTransform.MakeTranslation(0, 0);
});
uiViewPropertyAnimator.AddCompletion(p =>
{
finished = true;
});
uiViewPropertyAnimator.StartAnimation();
});
while (!finished)
await Task.Delay(10);
}
On iOS, you need to first translate the transform to its start position. Then, inside UIViewPropertyAnimator
, you need to specify the final transform so iOS can carry out the animation. Forms should not be aware of native property changes during the animation begin and end phases.
In essence, all of this hacky code is trying to bypass layers of Forms code that degrade animation performance.
@adrianknight89 interesting, will have a look at it. thanks!
I was trying to do some animations on complex views and i had to stop it immediately :(
So i found this issue and investigated the animation layer in forms: i had no idea that was implemented with an internal timer, completely skipping the native implementations :(
So i tried to compare some small animations with the forms engine and the native ones....
Ouch, the results are quite noticeable: even small animations are much more smooth using the native framework.
Maybe the community can help to create a more modern and performant engine for animations, lets see if the forms teams will ever approve this request :)
@GiampaoloGabba
Maybe the community can help to create a more modern and performant engine for animations, lets see if the forms teams will ever approve this request :)
Honestly, this should not be left to the community. While I understand Forms is an open source project, big corporations like Microsoft should be expected to hire people and develop a full-fledged cross-platform framework, especially considering Microsoft needs to attract more startups to the Azure ecosystem.
I'm extremely worried about the future of Xamarin Forms and recently decided to give up after many many years of contributing to this project. Right now, I'm migrating my code base to Xamarin.Android and Xamarin.iOS and noticing visible changes with respect to performance and layouting. With nearly 2000 open issues (some of them are very serious indeed) and a botched CollectionView
implementation, I don't see how anyone can deliver Forms production code and go to bed at night.
I've implemented my own UICollectionView
and RecyclerView
instead of using CollectionView
and also started using SDWebImage
and Glide
instead of FFImageLoading
, and I'm never going back. Finally, no more terrible animations. :)
Cheers.
@adrianknight89 I’ve sent you an email. Let’s talk. I’d really like to see your performance comparisons and get to the bottom of this. We should be able to achieve the same performance since all those same controls you note are either being used or may be substituted.
I have to say that in ios the animations are quite smooth (not as native, but they are good), in android on the other hand... they are a bit jittering, not fluid at all.
Maybe its just me, 'cause it seems that no one else is interested in this issue :(
Lately i was experimenting some simple UI with other cross-platforms frameworks. The custom animations in Xamarin Forms doesnt felt "natural" and fluid. I dont know... now that i noted this, I cant stop to see it in every app i developed :) But, again, maybe its just me...
Duplicate of #6033
Is this really a duplicate of #6033? This is about hw accelerated animations while #6033 just mentions more advanced page transitions.
Most helpful comment
@jrahma I believe there is an existing issue / PR for what you need. This issue is different in that I want a better animation framework that hands off as much work as possible to the native layers to do basic translate, scale, fade, etc. So, when I do something like:
this animation should be smooth when
view1
andview2
are complex instead of simple box views or buttons.I've recently created a simple, hacky dependency service that animates views for me. The animations are 10x better compared to using Xamarin Forms' animation framework. I directly use
ObjectAnimator
on Android andUIViewPropertyAnimator
on iOS. It does the job for me for my use case, but it skips a lot of visual element tracking Forms does, so it's not for production use. :)