如何用FlyoutPage替换Shell导航并保留原有菜单结构?
替换MAUI Shell导航为FlyoutPage实现相同菜单结构(解决页面实例复用问题)
完全可以通过替换为FlyoutPage来实现与原Shell一致的菜单结构,同时解决页面实例复用的问题。以下是对应实现方案:
核心思路
原Shell的结构分为两部分:
- 浮出层菜单:包含一个带标签导航的
Information组,以及三个独立页面(Enquiry、Search、Update) - 标签导航:
Information组下的四个页面(Home、Favourite、Recommended、Loans)
用FlyoutPage实现时,左侧浮出层用列表展示所有菜单选项,右侧内容区域根据选中项切换:选中Information组内的页面时加载带标签页的TabbedPage,选中其他独立项时直接加载对应页面实例(每次创建新实例,避免复用)。
实现代码
1. FlyoutPage主页面(MainFlyoutPage.xaml)
<?xml version="1.0" encoding="UTF-8" ?> <FlyoutPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:LibraryAppM.Views" x:Class="LibraryAppM.MainFlyoutPage" Title="LibraryAppM"> <!-- 左侧浮出层菜单 --> <FlyoutPage.Flyout> <ContentPage Title="Menu" BackgroundColor="White"> <ListView x:Name="MenuListView" ItemSelected="OnMenuItemSelected"> <ListView.ItemsSource> <x:Array Type="{x:Type local:MenuOption}"> <!-- Information组标识 --> <local:MenuOption Title="Information" Icon="lib_pic.jpg" IsGroup="True"/> <local:MenuOption Title="Home" Icon="home.png" TargetType="{x:Type local:MainPage}"/> <local:MenuOption Title="Favourite" Icon="favourite.jpeg" TargetType="{x:Type local:FavouritePage}"/> <local:MenuOption Title="Recommended" Icon="lib_pic.jpg" TargetType="{x:Type local:RecommendedPage}"/> <local:MenuOption Title="Loans" Icon="lib_pic.jpg" TargetType="{x:Type local:LoansPage}"/> <!-- 独立页面 --> <local:MenuOption Title="Enquiry" Icon="enquiry.png" TargetType="{x:Type local:EnquiryPage}"/> <local:MenuOption Title="Search" Icon="search.png" TargetType="{x:Type local:SearchPage}"/> <local:MenuOption Title="Update" Icon="update.png" TargetType="{x:Type local:UpdatePage}"/> </x:Array> </ListView.ItemsSource> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout Orientation="Horizontal" Padding="15,10"> <Image Source="{Binding Icon}" WidthRequest="25" HeightRequest="25"/> <Label Text="{Binding Title}" Margin="10,0" VerticalOptions="Center"/> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage> </FlyoutPage.Flyout> <!-- 默认显示的内容页 --> <FlyoutPage.Detail> <NavigationPage> <x:Arguments> <local:MainPage/> </x:Arguments> </NavigationPage> </FlyoutPage.Detail> </FlyoutPage>
2. 菜单选项模型(MenuOption.cs)
namespace LibraryAppM.Views { public class MenuOption { public string Title { get; set; } public string Icon { get; set; } public Type TargetType { get; set; } public bool IsGroup { get; set; } = false; } }
3. FlyoutPage后台代码(MainFlyoutPage.xaml.cs)
namespace LibraryAppM { public partial class MainFlyoutPage : FlyoutPage { public MainFlyoutPage() { InitializeComponent(); } private void OnMenuItemSelected(object sender, SelectedItemChangedEventArgs e) { var option = e.SelectedItem as MenuOption; if (option == null || option.IsGroup) return; // 每次创建新页面实例,彻底避免复用 Page targetPage = (Page)Activator.CreateInstance(option.TargetType); // 判断是否为Information组内页面,切换对应内容 var infoPageTypes = new[] { typeof(MainPage), typeof(FavouritePage), typeof(RecommendedPage), typeof(LoansPage) }; if (infoPageTypes.Contains(option.TargetType)) { var tabbedPage = new TabbedPage { Children = { new MainPage { Title = "Home", IconImageSource = "home.png" }, new FavouritePage { Title = "Favourite", IconImageSource = "favourite.jpeg" }, new RecommendedPage { Title = "Recommended", IconImageSource = "lib_pic.jpg" }, new LoansPage { Title = "Loans", IconImageSource = "lib_pic.jpg" } } }; // 切换到选中的标签页 tabbedPage.CurrentPage = tabbedPage.Children.First(c => c.GetType() == option.TargetType); Detail = new NavigationPage(tabbedPage); } else { Detail = new NavigationPage(targetPage); } IsPresented = false; } } }
4. 更新App启动入口(App.xaml.cs)
namespace LibraryAppM { public partial class App : Application { public App() { InitializeComponent(); // 替换原Shell为FlyoutPage MainPage = new MainFlyoutPage(); } } }
关键说明
- 通过
Activator.CreateInstance每次创建新页面实例,彻底解决Shell默认复用页面的问题 - 左侧菜单完整还原了原Shell的选项结构,包括
Information组的层级展示 - 标签导航通过
TabbedPage实现,与原Shell的Tab交互行为一致
内容的提问来源于stack exchange,提问作者user3017691
相关产品推荐
相关产品推荐

