zoukankan      html  css  js  c++  java
  • 张高兴的 UWP 开发笔记:汉堡菜单进阶

      不同于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,解决方案结构如下。(GitHub https://github.com/ZhangGaoxing/uwp-demo/tree/master/HamburgerDemo

      先创建一个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="&#xE700;" 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;
            }
        }
    }

      运行效果图如下

  • 相关阅读:
    react-redux
    Vue中常用的UI框架
    vue中router与route的区别
    H5新增input属性
    H5新增的input类型
    菜鸡对作用域链的理解
    自己对路由的一些理解
    浏览器缓存
    黄瓜的不定期更新面试题
    ajax封装
  • 原文地址:https://www.cnblogs.com/zhanggaoxing/p/6218717.html
Copyright © 2011-2022 走看看