Compartilhar via


Xamarin.Forms Página de submenu

Uma página de submenu normalmente exibe uma lista de itens, conforme mostrado nas seguintes capturas de tela:

Componentes da página do submenu

A localização da lista de itens é idêntico em cada plataforma e selecionar um dos itens navegará até a página de detalhes correspondente. Além disso, a página do submenu também apresenta uma barra de navegação que contém um botão que pode ser usado para navegar até a página de detalhes ativa:

  • No iOS, a barra de navegação está presente na parte superior da página e tem um botão que navega até a página de detalhes. Além disso, a página de detalhes ativa pode ser navegada deslizando o submenu para a esquerda.
  • No Android, a barra de navegação está presente na parte superior da página e exibe um título, um ícone e um botão que navega até a página de detalhes. O ícone é definido no atributo [Activity] que decora a classe MainActivity no projeto específico da plataforma Android. Além disso, a página de detalhes ativa pode ser navegada deslizando a página do submenu para a esquerda, tocando na página de detalhes na extremidade direita da tela e tocando no botão Voltar na parte inferior da tela.
  • Na UWP (Plataforma Universal do Windows), a barra de navegação está presente na parte superior da página e tem um botão que navega até a página de detalhes.

Uma página de detalhes exibe dados que correspondem ao item selecionado na página de submenu, e os componentes principais da página de detalhes são mostrados nas seguintes capturas de tela:

Componentes da página de detalhes

A página de detalhes contém uma barra de navegação, cujo conteúdo dependem da plataforma:

  • No iOS, a barra de navegação está presente na parte superior da página e exibe um título, e tem um botão que retorna à página do submenu, desde que a ocorrência da página de detalhes esteja encapsulada na NavigationPage instância. Além disso, a página do submenu pode ser retornada deslizando a página de detalhes para a direita.
  • No Android, uma barra de navegação está presente na parte superior da página e exibe um título, um ícone e um botão que retorna à página do submenu. O ícone é definido no atributo [Activity] que decora a classe MainActivity no projeto específico da plataforma Android.
  • Na UWP, a barra de navegação está presente na parte superior da página e exibe um título e tem um botão que retorna à página do submenu.

O comportamento da experiência de navegação entre o submenu e as páginas de detalhes depende da plataforma:

  • No iOS, a página de detalhes desliza para a direita enquanto a página do submenu desliza a partir da esquerda, e a parte esquerda da página de detalhes ainda está visível.
  • No Android, os detalhes e as páginas do submenu são sobrepostos uns aos outros.
  • Na UWP, a página do submenu desliza da parte restante da página de detalhes, desde que a FlyoutLayoutBehavior propriedade esteja definida como Popover.

Comportamento semelhante será observado no modo paisagem, exceto que a página de submenu no iOS e Android tem uma largura semelhante à página de submenu no modo retrato, portanto, mais da página de detalhes ficará visível.

Para obter informações sobre como controlar o comportamento de navegação, consulte Controlar o comportamento do layout de página de detalhes.

Criar uma FlyoutPage

A FlyoutPage contém Flyout e Detail propriedades que são ambas do tipo Page, que são usadas para obter e definir as páginas de submenu e detalhes, respectivamente.

Importante

Um FlyoutPage foi criado para ser uma página raiz e usá-la como uma página filho em outros tipos de página pode resultar em comportamento inesperado e inconsistente. Além disso, é recomendável que a página de submenu de um FlyoutPage seja sempre uma ContentPage instância e que a página de detalhes seja preenchida apenas com TabbedPage, NavigationPagee ContentPage instâncias. Isso ajudará a garantir uma experiência do usuário consistente em todas as plataformas.

O exemplo de código XAML a seguir mostra um FlyoutPage que define as propriedades Flyout e Detail:

<FlyoutPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:local="clr-namespace:FlyoutPageNavigation;assembly=FlyoutPageNavigation"
            x:Class="FlyoutPageNavigation.MainPage">
    <FlyoutPage.Flyout>
        <local:FlyoutMenuPage x:Name="flyoutPage" />
    </FlyoutPage.Flyout>
    <FlyoutPage.Detail>
        <NavigationPage>
            <x:Arguments>
                <local:ContactsPage />
            </x:Arguments>
        </NavigationPage>
    </FlyoutPage.Detail>
</FlyoutPage>

O seguinte exemplo de código mostra a FlyoutPage equivalente criada em C#:

public class MainPageCS : FlyoutPage
{
    FlyoutMenuPageCS flyoutPage;

    public MainPageCS()
    {
        flyoutPage = new FlyoutMenuPageCS();
        Flyout = flyoutPage;
        Detail = new NavigationPage(new ContactsPageCS());
        ...
    }
    ...
}    

A propriedade Flyout está definida como uma instância ContentPage. A propriedade Detail está definida como uma NavigationPage que contém uma instância ContentPage.

Criar a página de submenu

O exemplo de código XAML a seguir mostra a declaração do objeto FlyoutMenuPage, referenciado por meio da propriedade Flyout:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="using:FlyoutPageNavigation"
             x:Class="FlyoutPageNavigation.FlyoutMenuPage"
             Padding="0,40,0,0"
             IconImageSource="hamburger.png"
             Title="Personal Organiser">
    <StackLayout>
        <ListView x:Name="listView" x:FieldModifier="public">
            <ListView.ItemsSource>
                <x:Array Type="{x:Type local:FlyoutPageItem}">
                    <local:FlyoutPageItem Title="Contacts" IconSource="contacts.png" TargetType="{x:Type local:ContactsPage}" />
                    <local:FlyoutPageItem Title="TodoList" IconSource="todo.png" TargetType="{x:Type local:TodoListPage}" />
                    <local:FlyoutPageItem Title="Reminders" IconSource="reminders.png" TargetType="{x:Type local:ReminderPage}" />
                </x:Array>
            </ListView.ItemsSource>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid Padding="5,10">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="30"/>
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Image Source="{Binding IconSource}" />
                            <Label Grid.Column="1" Text="{Binding Title}" />
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

A página consiste em um ListView que é preenchido com dados em XAML definindo sua ItemsSource propriedade para uma matriz de FlyoutPageItem objetos. Cada FlyoutPageItem define propriedades Title, IconSource e TargetType.

Um DataTemplate é atribuído à propriedade ListView.ItemTemplate, para exibir cada FlyoutPageItem. O DataTemplate contém um ViewCell que consiste em um Image e em um Label. O Image exibe o valor da propriedade IconSource, e o Label exibe o valor da propriedade Title, para cada FlyoutPageItem.

A página tem seu conjunto de propriedades Title e IconImageSource. O ícone será exibido na página de detalhes, desde que ela tenha uma barra de título. Isso deve ser habilitado no iOS encapsulando a instância da página de detalhes em uma instância NavigationPage.

Observação

A página Flyout deve ter a propriedade Title definida ou ocorrerá uma exceção.

O exemplo de código a seguir mostra a página equivalente criada em C#:

public class FlyoutMenuPageCS : ContentPage
{
    ListView listView;
    public ListView ListView { get { return listView; } }

    public FlyoutMenuPageCS()
    {
        var flyoutPageItems = new List<FlyoutPageItem>();
        flyoutPageItems.Add(new FlyoutPageItem
        {
            Title = "Contacts",
            IconSource = "contacts.png",
            TargetType = typeof(ContactsPageCS)
        });
        flyoutPageItems.Add(new FlyoutPageItem
        {
            Title = "TodoList",
            IconSource = "todo.png",
            TargetType = typeof(TodoListPageCS)
        });
        flyoutPageItems.Add(new FlyoutPageItem
        {
            Title = "Reminders",
            IconSource = "reminders.png",
            TargetType = typeof(ReminderPageCS)
        });

        listView = new ListView
        {
            ItemsSource = flyoutPageItems,
            ItemTemplate = new DataTemplate(() =>
            {
                var grid = new Grid { Padding = new Thickness(5, 10) };
                grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(30) });
                grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });

                var image = new Image();
                image.SetBinding(Image.SourceProperty, "IconSource");
                var label = new Label { VerticalOptions = LayoutOptions.FillAndExpand };
                label.SetBinding(Label.TextProperty, "Title");

                grid.Children.Add(image);
                grid.Children.Add(label, 1, 0);

                return new ViewCell { View = grid };
            }),
            SeparatorVisibility = SeparatorVisibility.None
        };

        IconImageSource = "hamburger.png";
        Title = "Personal Organiser";
        Padding = new Thickness(0, 40, 0, 0);
        Content = new StackLayout
        {
            Children = { listView }
        };
    }
}

As capturas de tela a seguir mostram a página do submenu em cada plataforma:

Exemplo de página de submenu

Criar e exibir a página de detalhes

A instância FlyoutMenuPage contém uma propriedade ListView que expõe a instância ListView para que a instância MainPageFlyoutPage possa registrar um manipulador de eventos para manipular o evento ItemSelected. Isso permite que a instância MainPage defina a propriedade Detail como a página que representa o item ListView selecionado. O exemplo de código a seguir mostra o manipulador de eventos:

public partial class MainPage : FlyoutPage
{
    public MainPage()
    {
        ...
        flyoutPage.listView.ItemSelected += OnItemSelected;
    }

    void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        var item = e.SelectedItem as FlyoutPageItem;
        if (item != null)
        {
            Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
            flyoutPage.listView.SelectedItem = null;
            IsPresented = false;
        }
    }
}

O método OnItemSelected executa as seguintes ações:

  • Ele recupera o SelectedItem da instância ListView e, contanto que não seja null, define a página de detalhes como uma nova instância do tipo de página armazenado na propriedade TargetType do FlyoutPageItem. O tipo de página é encapsulado em uma instância NavigationPage para garantir que o ícone referenciado por meio da propriedade IconImageSource no FlyoutMenuPage seja mostrado na página de detalhes no iOS.
  • O item selecionado no ListView é definido como null para garantir que nenhum dos itens ListView serão selecionados na próxima vez em que o FlyoutMenuPage for apresentado.
  • A página de detalhes é apresentada ao usuário definindo a propriedade FlyoutPage.IsPresented como false. Essa propriedade controla se o submenu ou a página de detalhes é apresentada. Ele deve ser definido para true exibir a página do submenu e para false exibir a página de detalhes.

As capturas de tela a seguir mostram a página de detalhes, que é mostrada ContactPage depois de selecionada na página do submenu:

Exemplo de página de detalhes

Controlar o comportamento do layout de página de detalhes

A forma como o FlyoutPage gerencia o submenu e as páginas de detalhes depende se o aplicativo está sendo executado em um telefone ou tablet, da orientação do dispositivo e do valor da FlyoutLayoutBehavior propriedade. Essa propriedade determina como a página de detalhes será exibida. Os valores possíveis são:

  • Default – As páginas são exibidas usando o padrão da plataforma.
  • Popover – A página de detalhes cobre ou cobre parcialmente a página do submenu.
  • Split – A página do submenu é exibida à esquerda e a página de detalhes está à direita.
  • SplitOnLandscape – Uma tela dividida é usada quando o dispositivo está na orientação paisagem.
  • SplitOnPortrait – Uma tela dividida é usada quando o dispositivo está na orientação retrato.

O exemplo de código XAML a seguir demonstra como definir a propriedade FlyoutLayoutBehavior em um FlyoutPage:

<FlyoutPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            x:Class="FlyoutPageNavigation.MainPage"
            FlyoutLayoutBehavior="Popover">
  ...
</FlyoutPage>

O seguinte exemplo de código mostra a FlyoutPage equivalente criada em C#:

public class MainPageCS : FlyoutPage
{
    FlyoutMenuPageCS flyoutPage;

    public MainPageCS()
    {
        ...
        FlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover;
    }
}

Importante

O valor da propriedade afeta apenas aplicativos em execução em tablets ou na área de FlyoutLayoutBehavior trabalho. Aplicativos rodando em celulares sempre têm o Popover comportamento.