Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Time lag before closing Shell flyout menu #7521

Open
gnout opened this issue Sep 14, 2019 · 51 comments
Open

Time lag before closing Shell flyout menu #7521

gnout opened this issue Sep 14, 2019 · 51 comments

Comments

@gnout
Copy link

gnout commented Sep 14, 2019

Description

I created a new project in VS just by choosing the Shell template. I converted the AppShell to have flyout menus instead of tabs.
In the attached screen cast, when I tapped on the item that is currently displayed (the first tap is on the about page) then the side menu closes very smoothly which is the expected behavior.
When I tap on the second item (which is not currently displayed) then there is lag before the side menu closes. It seems as if the app is frozen for a few milliseconds.

Expected Behavior

I was expecting the closing of the side menu, in all cases, to be smooth

Actual Behavior

When tapping on one of the flyout menu items (not the one that is currently visible), there is a time lag before the flyout menu is closed and it looks (for a few miliseconds) that is app freezes. This behavior is displayed also to views that don;t have any data (i.e the About page)

Basic Information

  • Version with issue: 4.2.0.778463
  • Last known good version:
  • IDE:
  • Platform Target Frameworks:
    • Android: 9.0
  • Android Support Library Version: 28.0.01
  • Affected Devices: Nokia one 3.1, Samsung Galaxy J3

Screenshots

Screen cats is from an actual device and not an emulator

screencast.zip

@pauldipietro pauldipietro added this to New in Triage Sep 14, 2019
@jsuarezruiz jsuarezruiz added a/shell 🐚 p/Android s/unverified New report that has yet to be verified t/bug 🐛 labels Sep 16, 2019
@hartez hartez removed the s/unverified New report that has yet to be verified label Sep 19, 2019
@hartez hartez added this to To do in Android Ready For Work via automation Sep 19, 2019
@hartez hartez removed this from New in Triage Sep 19, 2019
@hartez hartez added the e/3 🕒 3 label Sep 19, 2019
@lv1il0s
Copy link

lv1il0s commented Sep 28, 2019

Seems related to #5216 (which is closed but apparently not resolved). I'm experiencing the same issue on physical devices (Samsung S8, A3, Sony Z1 Compact) and emulators. On the other hand, iOS seems to be smooth. I hope this issue will be looked into soon.

@wagenheimer
Copy link

I also have this problem!

@Mikilll94
Copy link

Is it going to be fixed? This problem exists from the very beginning and it makes flyout unusable.

@denzerd
Copy link

denzerd commented Nov 7, 2019

I have the same problem with a really simple setup.
I assume this won't be fixed it is the same bad behaviour as it was for many years with the MasterDetailPage.
The problem is that the rendering of the underlying ContentPage takes that much time that the animation of the menu is interrupted. But even with an empty content page the rendering is not fast enough to not have at least a small stutter. And I'm on a Galaxy S8 which should be powerful enough.
I'm looking for a way to apply the MasterDetailPage workaround to this (a short delay before actually closing the menu), no luck so far.

@VirtualNomad00
Copy link

Guess it's still not solved, which is a bit frustrating as this is a major UX issue

@Mikilll94
Copy link

@samhouts @jfversluis @davidortinau

@RedChops
Copy link

RedChops commented Feb 20, 2020

Moving all pages except for one top level ShellContent from the Flyout Menu to MenuItem, navigating to them with GoToAsync, and manually closing the menu is significantly more performant. It's crazy, the performance by going this route is probably on-par with the iOS experience.

There is still an always noticeable shutter when going back to the home page which looks pretty sloppy. This is very unfortunate, especially since it seems like navigation is pretty central to the whole Shell interface. It appears to be a performance hitch related to pushing a new page on to the root of the navigation stack alone.
I found above to be not entirely correct actually. The hitch on back navigation to the home page in my case was caused by a logic problem issue causing the OnAppearing method to always fire off a 'load data' command. It still doesn't feel like a good behavior though, even if the data was actually needed to load each time, it's only setting up a couple layouts.

@PureWeen PureWeen moved this from Backlog to To do (blockers) in Shell Feb 27, 2020
@DanKyungu
Copy link

DanKyungu commented Feb 28, 2020

@PureWeen, can you have an alternative to avoid this lag because we must go in production and i need to know if there is something we can do until the issue to be resolved, if not we'll have to move to the default MasterDetail Navigation...

@Mikilll94
Copy link

Mikilll94 commented Feb 28, 2020

@DanKyungu
It seems that there is no workaround. You need to go back to the old Master Detail page.

It's very sad that the Xamarin team is enjoyed with the Shell but with this bug, the Shell is really unusable because you cannot use the flyout.

@wagenheimer
Copy link

This bug is really annoying! I don't understand why something so critical seems to be ignored.

@samhouts
Copy link
Member

We're definitely not ignoring it! We've marked this as one of our highest priority Shell issues to resolve in the near future. If we discover a workaround in the meantime, we will post it here. Thanks for your patience!

@Jason424242
Copy link

Jason424242 commented Mar 12, 2020

I have also noticed a similar looking stutter on the Google Play store and the Outlook app. Google Play store especially when I select "My Apps & games" off the menu. Outlook sometimes when I choose a new folder. I thought it may be an inherent Android problem when starting a network fetch while an animation is running.

I just tried some things out in the debugger and the animation does not begin until OnAppearing has completed. Maybe a way to kick off my async refresh after the animation completes would help.

@nhadro
Copy link

nhadro commented Mar 16, 2020

This ia a really big issue for us. We have to release in a month, any idea if something might be in place to fix this before then? I really don't want to go back to MasterDetail.

@tossingc
Copy link

tossingc commented Apr 1, 2020

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:

  1. override OnPropertyChanged and store the last time the FlyoutIsPresented property was set to false
  2. override OnNavigating and if the last time the FlyoutIsPresented property was set to false is less than some value (using 1000ms in the code below), then assume the Flyout was just hidden and perform the following:
  3. cancel the navigation
  4. set FlyoutIsPresented to false
  5. raise OnPropertyChanged for the FlyoutIsPresented to trigger the ShellFlyoutRenderer to close the drawer
  6. wait a brief period for the flyout to close
  7. set a flag that we cancelled the navigation so we know to skip this check on the next call to OnNavigating
  8. re-run the original navigation in the arguments passed to OnNavigating the first time
	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);
		}
		
		...
	}

@nhadro @wagenheimer @Mikilll94 @DanKyungu @VirtualNomad00 @denzerd @lv1il0s @gnout

@whitedevils
Copy link

news about resolution? is very annoying this problem. :(

@JAdeloye
Copy link

Any update on this, has been here a while and really should be resolved?

@samhouts samhouts added this to To do in Sprint 171 May 21, 2020
@DanKyungu
Copy link

@AndreasReitberger
Copy link

I'm still facing this issue. Anything new on this one? iOS is working fine, only Android is lagging behind...
Thanks!

@ghost
Copy link

ghost commented Jan 9, 2021

Opened from one year !
Nice team from Microsoft 👍

@Nelo-cool
Copy link

Opened from one year !
Nice team from Microsoft 👍

Good boys! :) 🥇

@subhadrajain
Copy link

subhadrajain commented Mar 21, 2021

Please fix this.
I will lose my clients

@pictos
Copy link
Contributor

pictos commented Mar 21, 2021

@subhadrajain does this workaround doesn't work for you?#7521 (comment)

@holecekp
Copy link

I have tried the mentioned workaround and it did not work for me. It fixed the animation, but instead, it introduced a big lag before the new page was opened. So the overall user experience was equally bad :-(

@pictos
Copy link
Contributor

pictos commented Mar 21, 2021

@holecekp this one also? #7521 (comment)

Also, could you share a repro? I couldn't reproduce this issue locally in any Shell app that I made.

@subhadrajain
Copy link

@pictos 7 out of 10 times it is working fine.

@sparer
Copy link

sparer commented Apr 20, 2021

I've produced this workaround which works sufficiently for my application. It just waits for the page to load before hiding the flyout. My app has a redirect when the app loads to request permissions if the app doesn't have them hence the 'redirected' bool. This was necessary because the flyout would show on a redirect even though the user hadn't clicked the hamburger icon. I can see that it might not work in some scenarios, such as long loading page, but as I said, for me it solves the problem sufficiently.

        private bool redirected;

        protected override void OnNavigating(ShellNavigatingEventArgs args)
        {
            if (Device.Android.Equals(Device.RuntimePlatform))
            {
                if (ShellNavigationSource.ShellSectionChanged.Equals(args.Source) && !redirected)
                {
                    FlyoutIsPresented = true;
                }
                redirected = true;
            }
            base.OnNavigating(args);
        }

        protected override void OnNavigated(ShellNavigatedEventArgs args)
        {
            if (Device.Android.Equals(Device.RuntimePlatform))
            {
                FlyoutIsPresented = false;
                redirected = false;
            }
            base.OnNavigated(args);
        }

@Jose-Develaw
Copy link

Jose-Develaw commented May 20, 2021

Hi, everyone:

I have modified a bit some code I saw here and I obtained a pretty good result. Try this:

protected async override void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            base.OnPropertyChanged(propertyName);
            if (propertyName.Equals("CurrentItem") && Device.RuntimePlatform == Device.Android && this.CurrentState?.Location.OriginalString != "//loginPage")
            {
                FlyoutIsPresented = true;
                await Task.Delay(300);
                FlyoutIsPresented = false;
                
            }
          
        }

The <<this.CurrentState?.Location.OriginalString != "//loginPage">> thing is intended to avoid the flyout menu to appear the first time I log in.

Let me know it this works for you @subhadrajain @pictos @holecekp

@Reddyo
Copy link

Reddyo commented May 31, 2021

Also hoping this gets an official fix.. I had to combine some of the solutions here to get something that worked for me. Primarily it is Jose-Develaw's solution just above, but adding the extra condition did not stop the flyout from opening on startup for me. I also did not like the idea of omitting the fix for certain pages, so I changed it like so to avoid it triggering at startup:

bool startUp = true;
protected override void OnNavigated(ShellNavigatedEventArgs args)
{
    base.OnNavigated(args);
    startUp = false;
}

protected async override void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
    base.OnPropertyChanged(propertyName);
    if (!startUp && propertyName.Equals("CurrentItem") && Device.RuntimePlatform == Device.Android)
    {
        FlyoutIsPresented = true;
        await System.Threading.Tasks.Task.Delay(300);
        FlyoutIsPresented = false;
    }
}

OnNavigated() gets called after the initial calls to OnPropertyChanged() for "CurrentItem" so that is where the "startup" flag is updated to false.

@angelru
Copy link

angelru commented Jun 21, 2021

The same problem here, it seems to also have to do with the bindings on the page being loaded. I put a delay before "refresh my view" and it just finishes closing the menu and doesn't freeze while animating.

@RaghebAlashqar
Copy link

Also hoping this gets an official fix.. I had to combine some of the solutions here to get something that worked for me. Primarily it is Jose-Develaw's solution just above, but adding the extra condition did not stop the flyout from opening on startup for me. I also did not like the idea of omitting the fix for certain pages, so I changed it like so to avoid it triggering at startup:

bool startUp = true;
protected override void OnNavigated(ShellNavigatedEventArgs args)
{
    base.OnNavigated(args);
    startUp = false;
}

protected async override void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
    base.OnPropertyChanged(propertyName);
    if (!startUp && propertyName.Equals("CurrentItem") && Device.RuntimePlatform == Device.Android)
    {
        FlyoutIsPresented = true;
        await System.Threading.Tasks.Task.Delay(300);
        FlyoutIsPresented = false;
    }
}

OnNavigated() gets called after the initial calls to OnPropertyChanged() for "CurrentItem" so that is where the "startup" flag is updated to false.

Just tried this, It helped so much, No lagging and smooth transition.
Thank you very much

@AndreasReitberger
Copy link

@jsuarezruiz @hartez
Is this getting an official fix with SR5? This issue is almost open for two years..

@Nelo-cool
Copy link

@jsuarezruiz @hartez
Is this getting an official fix with SR5? This issue is almost open for two years..

There is a good saying among Russians. They have been waiting for the promised three years:)

@andersondamasio
Copy link

I also have this problem.
Any definitive solution?

@angelru
Copy link

angelru commented Aug 22, 2021

Maybe in MAUI it is corrected.

@Darlingtone
Copy link

Darlingtone commented Aug 22, 2021 via email

@PureWeen
Copy link
Contributor

Maybe in MAUI it is corrected.

It should be a lot better right now in MAUI. One of the issues here is that on XF shell aggressively disposes and recreates renderers every time you move between tabs/flyout items. With MAUI we aren't doing that and as you move around the native stacks are all maintained.

If anyone is up for testing this out a bit on MAUI let me know your results.

@codebreakerlegend2019
Copy link

To be fair for the one that is still on XF this should be fixed. Just saying.

@NemesisXB
Copy link

Another 6 months has past and still not fixed?

@NeilWork
Copy link

All the fixes presented here merely delays the lag to another point or hides it behind the flyout menu. Is there not a way to preload pages and just present them to a detail page similar to what the MasterDetail page did

@supershopping
Copy link

Finally I found this long thread… I was having this issue on XF. Now I move on to MAUI, still the similar experience. Anyone has comments or solutions for MAUI performance?

@kdgilang
Copy link

kdgilang commented Nov 6, 2022

Please fix this, I'm still facing the same issue on XS & MAUI.

@samhouts samhouts added the p/0 label Jan 6, 2023
@Hardikzinzala
Copy link

Please fix this, I'm still facing the same issue on MAUI.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Android Ready For Work
  
To do-High impact
Shell
  
To do (blockers)
Sprint 171
  
Returned to backlog
Development

No branches or pull requests