不同於Windows 8應用,Windows 10引入了“漢堡菜單”這一導航模式。說具體點,就拿官方的天氣應用來說,左上角三條橫杠的圖標外加一個SplitView控制項組成的這一導航模式就叫“漢堡菜單”。 本文討論的是如何實現官方的這一樣式(點擊後左側出現一個填充矩形),普通實現網上到處都是,有需要的 ...
不同於Windows 8應用,Windows 10引入了“漢堡菜單”這一導航模式。說具體點,就拿官方的天氣應用來說,左上角三條橫杠的圖標外加一個SplitView控制項組成的這一導航模式就叫“漢堡菜單”。
本文討論的是如何實現官方的這一樣式(點擊後左側出現一個填充矩形),普通實現網上到處都是,有需要的朋友自己百度下吧。
下麵將介紹兩種不同的實現方法,第一種最簡單的方法是直接使用 Template 10 模板,第二種就是純手寫了。
若有什麼不正確的地方望指正,大家共同討論。
1. Template 10 模板
使用 Template 10 模板可以快速建立出應用的框架,簡單快捷。(幫助文檔 https://github.com/Windows-XAML/Template10/wiki )
要使用 Template 10 首先點擊 Visual Studio “工具”菜單中的“擴展與更新”,搜索並安裝 Template 10(簡化搜索可以直接輸入t10)
安裝完成需要重啟,重啟後按下圖找到項目模板新建即可,使用很簡單,幫助文檔連接也在上方給出。
2. 手寫
先分析一下界面的構成,暫時不看標題欄,由一個設置了 Canvas.ZIndex 的 Button 和一個 SplitView 構成。SplitView.Pane 中又包含了兩個ListView(一級菜單和二級菜單)。ListView 里的每個 Item 又由 Rectangle,FontIcon,TextBlock 組成。見下圖
構成清晰之後實現的思路大概也就清晰了。下麵給一個簡單的Demo,解決方案結構如下。(相應的註釋在程式中給出)
先創建一個NavMenuItem類
using System; using System.ComponentModel; using Windows.UI.Xaml; using Windows.UI.Xaml.Media; namespace HamburgerDemo { class NavMenuItem : INotifyPropertyChanged { // 記錄圖標字體 public FontFamily FontFamily { get; set; } // 圖標的C#轉義代碼 public string Icon { get; set; } // 標題 public string Label { get; set; } // 導航頁 public Type DestPage { get; set; } // 用於左側矩形的顯示 private Visibility selected = Visibility.Collapsed; public Visibility Selected { get { return selected; } set { selected = value; this.OnPropertyChanged("Selected"); } } // 雙向綁定,用於更新矩形是否顯示 public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
主頁面框架代碼
<Page x:Class="HamburgerDemo.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HamburgerDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <!--菜單的數據模板--> <DataTemplate x:Key="DataTemplate"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="48" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Rectangle Fill="{ThemeResource SystemControlBackgroundAccentBrush}" Visibility="{Binding Selected, Mode=TwoWay}" HorizontalAlignment="Left" Width="5" Height="48" /> <FontIcon FontFamily="{Binding FontFamily}" Glyph="{Binding Icon}" Foreground="White" VerticalAlignment="Center" Margin="-2,0,0,0" Width="48" Height="48" /> <TextBlock Grid.Column="1" Text="{Binding Label}" Foreground="White" Margin="12,0,0,0" VerticalAlignment="Center" /> </Grid> </DataTemplate> <!--ListViewItem樣式定製--> <Style x:Key="NavMenuItemContainerStyle" TargetType="ListViewItem"> <Setter Property="MinWidth" Value="{StaticResource SplitViewCompactPaneThemeLength}"/> <Setter Property="Height" Value="48"/> <Setter Property="Padding" Value="0"/> <Setter Property="UseSystemFocusVisuals" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListViewItem"> <ListViewItemPresenter ContentTransitions="{TemplateBinding ContentTransitions}" Control.IsTemplateFocusTarget="True" SelectionCheckMarkVisualEnabled="False" PointerOverBackground="{ThemeResource SystemControlHighlightListLowBrush}" PointerOverForeground="{ThemeResource ListViewItemForegroundPointerOver}" SelectedBackground="Transparent" SelectedForeground="{ThemeResource SystemControlForegroundAccentBrush}" SelectedPointerOverBackground="{ThemeResource SystemControlHighlightListLowBrush}" PressedBackground="{ThemeResource SystemControlHighlightListMediumBrush}" SelectedPressedBackground="{ThemeResource SystemControlHighlightListMediumBrush}" DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" ContentMargin="{TemplateBinding Padding}"/> </ControlTemplate> </Setter.Value> </Setter> </Style> </Page.Resources> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <!--漢堡菜單開關--> <Button Name="PaneOpenButton" FontFamily="Segoe MDL2 Assets" Content="" Foreground="White" Background="{Binding BackgroundColor}" Width="48" Height="48" VerticalAlignment="Top" Canvas.ZIndex="100" /> <SplitView Name="RootSplitView" DisplayMode="CompactOverlay" CompactPaneLength="48" OpenPaneLength="256" IsPaneOpen="True"> <SplitView.Pane> <Grid Background="#CC000000"> <Grid.RowDefinitions> <!--空出Button的高度--> <RowDefinition Height="48" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <!--一級菜單--> <ListView Name="NavMenuPrimaryListView" Grid.Row="1" VerticalAlignment="Top" SelectionMode="None" IsItemClickEnabled="True" ItemTemplate="{StaticResource DataTemplate}" ItemContainerStyle="{StaticResource NavMenuItemContainerStyle}"/> <!--二級菜單--> <ListView Name="NavMenuSecondaryListView" Grid.Row="2" VerticalAlignment="Bottom" SelectionMode="None" IsItemClickEnabled="True" ItemTemplate="{StaticResource DataTemplate}" ItemContainerStyle="{StaticResource NavMenuItemContainerStyle}" BorderBrush="{ThemeResource SystemControlBackgroundAccentBrush}" BorderThickness="0,1,0,0" /> </Grid> </SplitView.Pane> <SplitView.Content> <Frame Name="RootFrame" /> </SplitView.Content> </SplitView> </Grid> </Page>
主頁面的後臺代碼
using HamburgerDemo.Views; using System.Collections.Generic; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; namespace HamburgerDemo { public sealed partial class MainPage : Page { // 為不同的菜單創建不同的List類型 private List<NavMenuItem> navMenuPrimaryItem = new List<NavMenuItem>( new[] { new NavMenuItem() { FontFamily = new FontFamily("Segoe MDL2 Assets"), Icon = "\xE10F", Label = "頁面1", Selected = Visibility.Visible, DestPage = typeof(Page1) }, new NavMenuItem() { FontFamily = new FontFamily("Segoe MDL2 Assets"), Icon = "\xE11A", Label = "頁面2", Selected = Visibility.Collapsed, DestPage = typeof(Page1) }, new NavMenuItem() { FontFamily = new FontFamily("Segoe MDL2 Assets"), Icon = "\xE121", Label = "頁面3", Selected = Visibility.Collapsed, DestPage = typeof(Page1) }, new NavMenuItem() { FontFamily = new FontFamily("Segoe MDL2 Assets"), Icon = "\xE122", Label = "頁面4", Selected = Visibility.Collapsed, DestPage = typeof(Page1) } }); private List<NavMenuItem> navMenuSecondaryItem = new List<NavMenuItem>( new[] { new NavMenuItem() { FontFamily = new FontFamily("Segoe MDL2 Assets"), Icon = "\xE713", Label = "設置", Selected = Visibility.Collapsed, DestPage = typeof(Page1) } }); public MainPage() { this.InitializeComponent(); // 綁定導航菜單 NavMenuPrimaryListView.ItemsSource = navMenuPrimaryItem; NavMenuSecondaryListView.ItemsSource = navMenuSecondaryItem; // SplitView 開關 PaneOpenButton.Click += (sender, args) => { RootSplitView.IsPaneOpen = !RootSplitView.IsPaneOpen; }; // 導航事件 NavMenuPrimaryListView.ItemClick += NavMenuListView_ItemClick; NavMenuSecondaryListView.ItemClick += NavMenuListView_ItemClick; // 預設頁 RootFrame.SourcePageType = typeof(Page1); } private void NavMenuListView_ItemClick(object sender, ItemClickEventArgs e) { // 遍歷,將選中Rectangle隱藏 foreach (var np in navMenuPrimaryItem) { np.Selected = Visibility.Collapsed; } foreach (var ns in navMenuSecondaryItem) { ns.Selected = Visibility.Collapsed; } NavMenuItem item = e.ClickedItem as NavMenuItem; // Rectangle顯示並導航 item.Selected = Visibility.Visible; if (item.DestPage != null) { RootFrame.Navigate(item.DestPage); } RootSplitView.IsPaneOpen = false; } } }
運行效果圖如下