On Android when selecting a flyout item, the animation is very bad. Everything is shown on the gif below.
The animation should be smooth.
The animation is clutchy.
My current working theory on this is that right now the code aggressively disposes all the content of any ShellItem you鈥檙e navigating away from and I鈥檓 pretty sure the overlap of that dispose code, create code, and drawer code causes the stutter. Basically when you click on a new item in the flyout the entire current item gets destroyed at the platform level and the item you clicked on gets created. This is my current working theory of the stutter.
We鈥檙e going to need to figure out the best way to balance startup performance and runtime performance. It鈥檚 much like the setOffscreenPageLimit concept on Android.
IMO this should be a high priority issue. Almost every app needs flyout and with this issue flyout on Android is completely unacceptable.
It's really very bad on Android, even to show simple pages. But it only happens the first time you open a page, further navigation after the page is already opened is a lot smoother.
@wagenheimer It's sad that Xamarin team does not prioritize this issue.
Is there something like "isFlyoutAnimating"? I think adding an Await to wait for the flyout to closes should help.
I have a workaround - it's not pretty, but it stops the flyout jitter on close. My hope is that it sheds some light to the development team on a fix for this and get others a temporary workaround.
It looks like the problem is that there is too much going on in the main thread while the flyout close transition is trying to run. (Android DrawerLayout CloseDrawer() animation)
NOTE: this workaround addresses the Xamarin Forms logic for creating and setting the page blocking the UI thread, but any other app logic running on the UI thread will cause the same jittery "close drawer" animation. One way to mitigate this would be to listen for FlyoutIsPresented to become true and pause any update logic running from running on the UI thread until FlyoutIsPresented has been false for some period. (i.e. 1000ms)
In your subclass of Shell:
public class AppShell : Shell
{
...
private DateTime LastFlyoutHiddenUtcDateTime { get; set; }
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == nameof(FlyoutIsPresented))
{
if (!FlyoutIsPresented)
{
LastFlyoutHiddenUtcDateTime = DateTime.UtcNow;
}
}
}
private bool WasNavigationCancelledToCloseFlyoutAndReRunAfterADelayToAvoidJitteryFlyoutCloseTransitionBug = false;
protected override async void OnNavigating(ShellNavigatingEventArgs args)
{
if (!WasNavigationCancelledToCloseFlyoutAndReRunAfterADelayToAvoidJitteryFlyoutCloseTransitionBug)
{
// if the above value is true, then this is the re-run navigation from the GoToAsync(args.Target) call below - skip this block this second pass through, as the flyout is now closed
if ((DateTime.UtcNow - LastFlyoutHiddenUtcDateTime).TotalMilliseconds < 1000)
{
args.Cancel();
FlyoutIsPresented = false;
OnPropertyChanged(nameof(FlyoutIsPresented));
await Task.Delay(300);
WasNavigationCancelledToCloseFlyoutAndReRunAfterADelayToAvoidJitteryFlyoutCloseTransitionBug = true;
// re-run the originally requested navigation
await GoToAsync(args.Target);
return;
}
}
WasNavigationCancelledToCloseFlyoutAndReRunAfterADelayToAvoidJitteryFlyoutCloseTransitionBug = false;
base.OnNavigating(args);
}
...
}
Most helpful comment
I have a workaround - it's not pretty, but it stops the flyout jitter on close. My hope is that it sheds some light to the development team on a fix for this and get others a temporary workaround.
It looks like the problem is that there is too much going on in the main thread while the flyout close transition is trying to run. (Android DrawerLayout CloseDrawer() animation)
NOTE: this workaround addresses the Xamarin Forms logic for creating and setting the page blocking the UI thread, but any other app logic running on the UI thread will cause the same jittery "close drawer" animation. One way to mitigate this would be to listen for FlyoutIsPresented to become true and pause any update logic running from running on the UI thread until FlyoutIsPresented has been false for some period. (i.e. 1000ms)
In your subclass of Shell: