Skip to content
Closed
20 changes: 17 additions & 3 deletions src/Controls/src/Core/Shell/ShellSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -844,10 +844,21 @@ protected virtual async Task OnPopToRootAsync(bool animated)
RequestType = NavigationRequestType.PopToRoot
};

InvokeNavigationRequest(args);
PresentedPageDisappearing();
var oldStack = _navStack;
_navStack = new List<Page> { null };

// NOTE:
// We intentionally raise PresentedPageAppearing (and thus SendPageAppearing/OnAppearing)
// before issuing the platform navigation request and awaiting its completion. This matches
// the behavior used for single-level Pop navigation and keeps Shell lifecycle events
// consistent across navigation patterns. At this point the root page may not yet be
// visually presented by the native stack (the pop-to-root animation can still be in
// progress), but Shell-level state (e.g., tab bar visibility) must already be updated
// so the platform reads the correct value when it commits the native navigation.
PresentedPageAppearing();
InvokeNavigationRequest(args);

if (args.Task != null)
await args.Task;

Expand All @@ -856,11 +867,14 @@ protected virtual async Task OnPopToRootAsync(bool animated)

for (int i = 1; i < oldStack.Count; i++)
{
oldStack[i].SendDisappearing();
// RemovePage is called for all pages. SendDisappearing is only called for
// intermediate pages; the top page's disappearing event was already fired
// by PresentedPageDisappearing() above to avoid duplicate lifecycle events.
if (i < oldStack.Count - 1)
oldStack[i].SendDisappearing();
RemovePage(oldStack[i]);
}

PresentedPageAppearing();
}

protected virtual Task OnPushAsync(Page page, bool animated)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
167 changes: 167 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue33351.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 33351, "Changing Shell Tab Visibility when navigating back multiple pages ignores Shell Tab Visibility", PlatformAffected.All)]
public class Issue33351 : Shell
{
public Issue33351()
{
Routing.RegisterRoute("Issue33351Page1", typeof(Issue33351Page1));
Routing.RegisterRoute("Issue33351Page2", typeof(Issue33351Page2));

var tabBar = new TabBar
{
Items =
{
new MyTab
{
Title = "Tab 1",
ContentTemplate = new DataTemplate(() => new Issue33351MainPage())
},
new ShellContent
{
Title = "Tab 2",
ContentTemplate = new DataTemplate(() => new Issue33351SecondTabPage())
}
}
};

Items.Add(tabBar);
}

class MyTab : ShellContent
{
protected override void OnAppearing()
{
base.OnAppearing();

if (this.Parent != null)
Shell.SetTabBarIsVisible(this.Parent, true);

Shell.Current.Navigating -= OnShellNavigating;
Shell.Current.Navigating += OnShellNavigating;
}

protected override void OnDisappearing()
{
base.OnDisappearing();

Shell.Current.Navigating -= OnShellNavigating;
}

void OnShellNavigating(object sender, ShellNavigatingEventArgs e)
{
if (this.Parent != null)
Shell.SetTabBarIsVisible(this.Parent, false);
}
}

class Issue33351MainPage : ContentPage
{
public Issue33351MainPage()
{
Title = "Main Page";
AutomationId = "RootPage";

var statusLabel = new Label
{
AutomationId = "TabBarVisibleLabel",
Text = "Tab Bar Visible"
};

var navigateButton = new Button
{
AutomationId = "PushPage1Button",
Text = "Go to Page 1",
HorizontalOptions = LayoutOptions.Fill
};

navigateButton.Clicked += async (s, e) =>
{
await Shell.Current.GoToAsync("Issue33351Page1");
};

Content = new VerticalStackLayout
{
Padding = new Thickness(20),
Spacing = 20,
Children = { statusLabel, navigateButton }
};
}
}

class Issue33351Page1 : ContentPage
{
public Issue33351Page1()
{
Title = "Page 1";

var statusLabel = new Label
{
AutomationId = "TabBarHiddenLabel",
Text = "Tab Bar Hidden"
};

var navigateButton = new Button
{
AutomationId = "PushPage2Button",
Text = "Go to Page 2",
HorizontalOptions = LayoutOptions.Fill
};

navigateButton.Clicked += async (s, e) =>
{
await Shell.Current.GoToAsync("Issue33351Page2");
};

Content = new VerticalStackLayout
{
Padding = new Thickness(20),
Spacing = 20,
Children = { statusLabel, navigateButton }
};
}
}

class Issue33351Page2 : ContentPage
{
public Issue33351Page2()
{
Title = "Page 2";
AutomationId = "Page2";

var statusLabel = new Label
{
AutomationId = "TabBarHiddenLabel2",
Text = "Tab Bar Hidden"
};

var popToRootButton = new Button
{
AutomationId = "PopToRootButton",
Text = "Go Back (../..)",
HorizontalOptions = LayoutOptions.Fill
};

popToRootButton.Clicked += async (s, e) =>
{
await Shell.Current.GoToAsync("../..");
};

Content = new VerticalStackLayout
{
Padding = new Thickness(20),
Spacing = 20,
Children = { statusLabel, popToRootButton }
};
}
}

class Issue33351SecondTabPage : ContentPage
{
public Issue33351SecondTabPage()
{
Title = "Tab 2";
Content = new Label { Text = "Tab 2" };
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue33351 : _IssuesUITest
{
public Issue33351(TestDevice testDevice) : base(testDevice)
{
}

public override string Issue => "Changing Shell Tab Visibility when navigating back multiple pages ignores Shell Tab Visibility";

[Test]
[Category(UITestCategories.Shell)]
public void TabBarVisibilityAfterMultiLevelPopToRoot()
{
App.WaitForElement("Tab 1");
App.Tap("Tab 1");

App.WaitForElement("PushPage1Button");
App.Tap("PushPage1Button");

App.WaitForElement("PushPage2Button");
App.Tap("PushPage2Button");

App.WaitForElement("PopToRootButton");
App.Tap("PopToRootButton");
App.WaitForElement("TabBarVisibleLabel");

VerifyScreenshot();
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading