Skrytí hlavičky NavigationView v UWP

Development WinUI XAML

6 years ago

Ovladací prvek NavigationView který byl přidán v aktualizaci Fall Creators Update pro Windows 10 je velmi užitečný nástroj pro vytváření uživatelsky přívětivé hamburger menu navigace, která zapadá do UX guidelines UWP aplikací. NavigationView obsahuje prostor pro hlavičku, kam můžete vložit titulek vaší stránky aplikace. Co když však hlavičku nechceme zobrazovat?

Minimální problém

NavigationView má vlastnost AlwaysShowHeader , která nám umožňuje specifikovat, zda chceme hlavičku vždy zobrazovat nebo ne. Tato vlastnost se chová přesně jak potřebujeme až do té doby, kdy okno aplikace zmenšíme a NavigationView se přepne do módu Minimal.

Minimal mode shows the header

V minimálním módu je prostor pro hlavičku zobrazen

Ikdyž je hlavička prázdná, náš obsah je posunut dolů, aby pro ni vytvořil místo. To není úplně uživatelsky přívětivé, především na malých displejích (jako telefonních), kde se každý pixel počítá.

Skrytý v šabloně

Když se zahloubáme do výchozího stylu NavigationView, můžeme zde najít následující XAML definici:

<ContentControl x:Name="HeaderContent" 
       ContentTemplate="{TemplateBinding HeaderTemplate}"
       Content="{TemplateBinding Header}" 
       HorizontalContentAlignment="Stretch" 
       IsTabStop="False"
       MinHeight="48"
       VerticalContentAlignment="Stretch"/>

Problém je poměrně zřejmý - vlastnost MinHeight hlavičky je nastavena na 48 efektivních pixelů. V módu Minimal je header vždy zobrazen a i v případě že nic neobsahuje, zabírá cenných 48 pixelů z výšky vaší aplikace. Řešení je velmi snadné – můžeme vlastnost MinHeight prostě odstranit.

The header is gone!

The header is gone!

S tímto řešením je hlavička "neviditelná", ale pokud do ni vložíme nějaký obsah, znovu ji můžeme snadno zobrazit. Samozřejme si musíme nyní dát pozor, že levý horní roh našeho obsahu může být zakryt tlačítkem pro otevření hamburger menu.Tento problém nástává pouze v módu Minimal, takže lze použít VisualStateTrigger a přidat požadované levé odsazení prvkům vaší stránky. Zde je zdrojový kód celého aktualizovaného Style. Můžete je také najít ve zdrojovém kódu k tomuto článku na GitHubu.

<Style x:Key="CustomNavigationMenuStyle" TargetType="NavigationView">
    <Setter Property="PaneToggleButtonStyle" Value="{StaticResource PaneToggleButtonStyle}"/>
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="HeaderTemplate">
        <Setter.Value>
            <DataTemplate>
                <Grid Margin="12,5,0,11" VerticalAlignment="Stretch">
                    <TextBlock x:Name="Header" Style="{StaticResource TitleTextBlockStyle}" Text="{Binding}" TextWrapping="NoWrap" VerticalAlignment="Bottom"/>
                </Grid>
            </DataTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="NavigationView">
                <Grid x:Name="RootGrid">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="DisplayModeGroup">
                            <VisualState x:Name="Compact"/>
                            <VisualState x:Name="Expanded">
                                <VisualState.Setters>
                                    <Setter Target="RootSplitView.PaneBackground" Value="{ThemeResource NavigationViewExpandedPaneBackground}"/>
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Minimal">
                                <VisualState.Setters>
                                    <Setter Target="HeaderContent.Margin" Value="48,0,0,0"/>
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="TogglePaneGroup">
                            <VisualState x:Name="TogglePaneButtonVisible"/>
                            <VisualState x:Name="TogglePaneButtonCollapsed">
                                <VisualState.Setters>
                                    <Setter Target="TogglePaneButton.Visibility" Value="Collapsed"/>
                                    <Setter Target="PaneContentGridToggleButtonRow.Height" Value="4"/>
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="HeaderGroup">
                            <VisualState x:Name="HeaderVisible"/>
                            <VisualState x:Name="HeaderCollapsed">
                                <VisualState.Setters>
                                    <Setter Target="HeaderContent.Visibility" Value="Collapsed"/>
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SettingsGroup">
                            <VisualState x:Name="SettingsVisible"/>
                            <VisualState x:Name="SettingsCollapsed">
                                <VisualState.Setters>
                                    <Setter Target="SettingsNavPaneItem.Visibility" Value="Collapsed"/>
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="AutoSuggestGroup">
                            <VisualState x:Name="AutoSuggestBoxVisible"/>
                            <VisualState x:Name="AutoSuggestBoxCollapsed">
                                <VisualState.Setters>
                                    <Setter Target="AutoSuggestArea.Visibility" Value="Collapsed"/>
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="PaneStateGroup">
                            <VisualState x:Name="NotClosedCompact"/>
                            <VisualState x:Name="ClosedCompact">
                                <VisualState.Setters>
                                    <Setter Target="PaneAutoSuggestBoxPresenter.Visibility" Value="Collapsed"/>
                                    <Setter Target="PaneAutoSuggestButton.Visibility" Value="Visible"/>
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="TitleBarVisibilityGroup">
                            <VisualState x:Name="TitleBarVisible"/>
                            <VisualState x:Name="TitleBarCollapsed">
                                <VisualState.Setters>
                                    <Setter Target="PaneButtonGrid.Margin" Value="0,32,0,0"/>
                                    <Setter Target="PaneContentGrid.Margin" Value="0,32,0,0"/>
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid HorizontalAlignment="Left" Margin="0,0,0,8" VerticalAlignment="Top" Width="{StaticResource PaneToggleButtonSize}" Canvas.ZIndex="100">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <Grid x:Name="TogglePaneTopPadding"/>
                        <Button x:Name="TogglePaneButton" AutomationProperties.LandmarkType="Navigation" Grid.Row="1" Style="{TemplateBinding PaneToggleButtonStyle}"/>
                    </Grid>
                    <SplitView x:Name="RootSplitView" Background="{TemplateBinding Background}" CompactPaneLength="{TemplateBinding CompactPaneLength}" DisplayMode="Inline" IsTabStop="False" IsPaneOpen="{Binding IsPaneOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" OpenPaneLength="{TemplateBinding OpenPaneLength}" PaneBackground="{ThemeResource NavigationViewDefaultPaneBackground}">
                        <SplitView.Pane>
                            <Grid x:Name="PaneContentGrid">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition x:Name="PaneContentGridToggleButtonRow" Height="56"/>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="8"/>
                                </Grid.RowDefinitions>
                                <Grid x:Name="ContentPaneTopPadding"/>
                                <Grid x:Name="AutoSuggestArea" Height="40" Grid.Row="2" VerticalAlignment="Center">
                                    <ContentControl x:Name="PaneAutoSuggestBoxPresenter" Content="{TemplateBinding AutoSuggestBox}" HorizontalContentAlignment="Stretch" IsTabStop="False" Margin="12,0,12,0" VerticalContentAlignment="Center"/>
                                    <Button x:Name="PaneAutoSuggestButton" Content="&#xE11A;" MinHeight="40" Style="{TemplateBinding PaneToggleButtonStyle}" Visibility="Collapsed" Width="{TemplateBinding CompactPaneLength}"/>
                                </Grid>
                                <NavigationViewList x:Name="MenuItemsHost" ItemContainerStyleSelector="{TemplateBinding MenuItemContainerStyleSelector}" ItemContainerStyle="{TemplateBinding MenuItemContainerStyle}" ItemTemplate="{TemplateBinding MenuItemTemplate}" IsItemClickEnabled="True" ItemsSource="{TemplateBinding MenuItemsSource}" ItemTemplateSelector="{TemplateBinding MenuItemTemplateSelector}" Margin="0,0,0,20" Grid.Row="3" SelectionMode="Single" SelectedItem="{TemplateBinding SelectedItem}"/>
                                <Border x:Name="FooterContentBorder" Child="{TemplateBinding PaneFooter}" Grid.Row="4"/>
                                <NavigationViewItem x:Name="SettingsNavPaneItem" Grid.Row="5">
                                    <NavigationViewItem.Icon>
                                        <SymbolIcon Symbol="Setting"/>
                                    </NavigationViewItem.Icon>
                                </NavigationViewItem>
                            </Grid>
                        </SplitView.Pane>
                        <Grid x:Name="ContentGrid">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <ContentControl x:Name="HeaderContent" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" HorizontalContentAlignment="Stretch" IsTabStop="False" VerticalContentAlignment="Stretch"/>
                            <ContentPresenter Content="{TemplateBinding Content}" Grid.Row="1"/>
                        </Grid>
                    </SplitView>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Ukázkový kód

Zdrojový kód k tomuto článku je k dispozici na mém GitHubu.

Shrnutí

Ukázali jsme si jak vynutit v NavigationView skrytí hlavičky i v módu Minimal aby obsah naší aplikace byl úplně bez hranic.