Search code examples
c#xamlmauiflyoutmaui-shell

.NET Maui how to do very specific thing in Flyout menu involving icons


Sorry about the bad title... I couldn't think of a way to explain what I'm trying to do in one sentence. Also note that the platform is entirely Android (I don't think it matters, but I could be wrong).

This is far easier to explain visually. The next three images are of two pages:

  1. Home page. Note the Flyout menu hamburger.
  2. Home page after flying out the Flyout menu.
  3. About page.

Description of current Flyout menu
I have a Flyout Menu. Currently there are two pages on the menu, Home and About. From the Home page, this is what it currently looks like:
enter image description here

Then I open the Flyout menu:
enter image description here

Click on the About page, and we get to the... About page, which looks like this:
enter image description here

What I'd like to change
The things I want to change are all on the About page. I'd like to:

  • remove the hamburger icon and exchange it for something else (a "back" button)
  • remove the title so the only thing that's on the nav bar is the new icon (this is trivial)
  • change the behavior of what happens when the hamburger-icon-changed-to-back-button-icon is pressed... instead of flying out a menu, have it return to the Home page.

This is what I'd like it to look like:
enter image description here

Current code
I'll show the following code:

  • AppShell.xaml, where I put in the code for both the Home and About page
  • AboutPage.xaml, which isn't interesting now, but might be a place I need to add code.
  • AboutPageViewModel.cs, where I add the method that corresponds to the action of pressing the "back" arrow in the Flyout menu (I'm not sure that this is the correct place to add this code).

Note that I'm relatively inexperienced with Maui, so there's a big possibility that I'm approaching everything incorrectly -- for example, maybe all of the Shell properties should be set in the page's respective xaml file instead of in AppShell.xaml?

The answers to questions like these I just made up. Anyways, here's the code in the state before I start trying all kinds of stuff achieve my objectives.

AppShell.xaml xml for the Home page:

    <FlyoutItem x:Name="HomePage"
                FlyoutDisplayOptions="AsMultipleItems">
        <ShellContent Title="Home"
                      ContentTemplate="{DataTemplate view:HomePage}"
                      FlyoutItemIsVisible="True"
                      Icon="home.png"
                      Route="HomePage"
                      Shell.BackgroundColor="#2e3292"
                      Shell.ForegroundColor="White"
                      Shell.NavBarIsVisible="True"
                      Shell.TitleColor="White" />
    </FlyoutItem>

AppShell.xaml, code for the About page:

    <FlyoutItem x:Name="FlyoutMenuItems"
                FlyoutDisplayOptions="AsMultipleItems">
        <ShellContent Title="About"
                      ContentTemplate="{DataTemplate view:AboutPage}"
                      FlyoutItemIsVisible="True"
                      Icon="about.png"
                      Route="AboutPage"
                      Shell.BackgroundColor="#2e3292"
                      Shell.NavBarIsVisible="True"
                      Shell.TitleColor="GhostWhite"/>
    </FlyoutItem>

AboutPage.xaml, not much to it so far:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="SandboxProject.View.AboutPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:viewmodel="clr-namespace:SandboxProject.ViewModel">

    <StackLayout Padding="10">
        <Label Margin="10,80,0,0"
            FontAttributes="Bold"
            FontSize="Large"
            Text="About WHAT?!?" />
    </StackLayout>
</ContentPage>

AboutPageViewModel.cs, is completely empty:

namespace SandboxProject.ViewModel;
public partial class AboutPageViewModel : ObservableObject{}

What have I tried?
Quite a bit. I'll give the example that made the most sense...

I'm pretty sure that I need to use BackButtonBehavior (go to the bottom of this page to read up on it), but I'm not using it correctly.

Here are the changes I made to About page's code in ApShell.xaml... I set the icon for FlyoutIcon to be the "about" icon (you know, the 'i' character) and I set the icon for the icon for the page itself to be a left arrow. I removed the title.

    <FlyoutItem x:Name="FlyoutMenuItems"
                FlyoutDisplayOptions="AsMultipleItems"
                FlyoutIcon="about.png">
        <ShellContent ContentTemplate="{DataTemplate view:AboutPage}"
                      FlyoutItemIsVisible="True"
                      Route="AboutPage"
                      Icon="leftarrow.png"
                      Shell.BackgroundColor="#2e3292"
                      Shell.NavBarIsVisible="True"/>
    </FlyoutItem>

I added these lines of code to AboutPage.xaml. This should bind the icon to a command Back:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    ...>

    <Shell.BackButtonBehavior>
        <BackButtonBehavior Command="{Binding BackCommand}" />
    </Shell.BackButtonBehavior>

    <StackLayout>
        <Label... />
    </StackLayout>
</ContentPage>

And here's the command in AboutPageViewModel.cs, Back, that should be triggered when the user clicks on the left arrow icon:

namespace SandboxProject.ViewModel;
public partial class AboutPageViewModel : ObservableObject
{
    [RelayCommand]
    private async Task Back() =>
        await Shell.Current.GoToAsync($"//{nameof(HomePage)}");
}

It doesn't work. The About pages navbar is empty. The string "About" is gone, which I wanted, but there's no icon, nothing to press.
enter image description here

If anyone could teach me, I'd appreciate it.

EDIT: SOLUTION
The following is the solution, as (mostly) suggested below by Monsieur Zheng. First, a reiteration of the problem.

A Home page. It has a Flyout menu that contains two menu options, "Home" and "About".
enter image description here

Usually, when the user presses the "About" page button in the Flyout menu, the resulting page has a hamburger icon at the top that, when pressed, opens the another Flyout menu, along with the "About" page title. It looks something like this:
enter image description here

However, what I want is the following:

  • icon for About isn't the same icon as it is in the Flyout menu. Instead of the "i" icon, it's a back arrow.
  • pressing the icon performs a different action than the action that it normally would. As a Flyout menu icon, it should reopen the Flyout menu, but I want it to go to a command (which takes it back to the Home page).
  • The title is removed. Instead of it saying "About" in the nav bar, it says... nothing!

Here's the solution:

AppShell.xaml, the "About" stuff:

    <FlyoutItem
        x:Name="FlyoutMenuItems"
        FlyoutDisplayOptions="AsMultipleItems"
        FlyoutIcon="about.png">
        <ShellContent
            Title="About"
            ContentTemplate="{DataTemplate view:AboutPage}"
            FlyoutItemIsVisible="True"
            Icon="about.png"
            Route="AboutPage"
            Shell.BackgroundColor="#FFFFFF" />
    </FlyoutItem>

About.xaml. The elements (and their respective nested elements) Shell.TitleView and Shell.BackButtonBehavior are the only different things than the original. It is weird that I needed Command="{Binding BackCommand}" in both elements...

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage ...>

    <Shell.TitleView>
        <ImageButton Command="{Binding BackCommand}"
                     HeightRequest="30"
                     HorizontalOptions="Start"
                     Source="leftarrow.png"
                     WidthRequest="30" />
    </Shell.TitleView>

    <Shell.BackButtonBehavior>
        <BackButtonBehavior Command="{Binding BackCommand}"
                            IconOverride="leftarrow.png" />
    </Shell.BackButtonBehavior>

    <StackLayout >
        <!-- "About" page stuff -->
    </StackLayout>
</ContentPage>

Here's what it looks like: enter image description here


Solution

  • It doesn't work. The About pages navbar is empty. The string "About" is gone, which I wanted, but there's no icon, nothing to press.

    For this, you can customize the TitleView by yourself. Here, we need to hide the default navigation bar and add Shell.TitleView element.

    <?xml version="1.0" encoding="utf-8" ?> 
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="MauiApp420.Pages.AboutPage"
                  x:Name="self"
                 NavigationPage.HasBackButton="False"
                 Shell.NavBarIsVisible="True"
                 xmlns:vms="clr-namespace:MauiApp420.ViewModels"
                 Title="AboutPage">
    
        <ContentPage.BindingContext>
            <vms:AboutPageViewModel></vms:AboutPageViewModel>
        </ContentPage.BindingContext>
    
        <Shell.TitleView>
            <HorizontalStackLayout Margin="0" >
                <ImageButton Source="backward_fill.png" WidthRequest="60" HeightRequest="60" Command="{Binding BackCommand}" Margin="0"
                   VerticalOptions="Center" />
    
                <Label Text="About" HorizontalOptions="Center" VerticalOptions="Center" Margin="10,0,10,0"></Label>
            </HorizontalStackLayout>
        </Shell.TitleView>
    
    
        <Shell.BackButtonBehavior>
            <BackButtonBehavior  IsVisible="False"  IsEnabled="False" Command="{Binding BackCommand}" />
        </Shell.BackButtonBehavior>
    
    
        <StackLayout Padding="10" BackgroundColor="Yellow">
            <Label Margin="10,80,0,0"
                FontAttributes="Bold"
                FontSize="Large"
                Text="About WHAT?!?" />
        </StackLayout>
    </ContentPage>
    

    Note:

    Here,I found we need to add Command="{Binding BackCommand}" for the BackButtonBehavior, otherwise the Hamberger icon will be displayed as well.

    For this problem, you can create an issue here.