Xamarin.Forms FlyoutPage

Baixar exemplo Baixar o exemplo

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

página submenu Componentes da página submenu Componentes

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 de 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 passando 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 passando o dedo da página do submenu para a esquerda, tocando na página de detalhes na extrema 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 do submenu e os componentes main da página de detalhes são mostrados nas seguintes capturas de tela:

Componentes de 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 para a página de submenu, desde que a instância da página de detalhes seja encapsulada na NavigationPage instância. Além disso, a página de submenu pode ser retornada passando o dedo da 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 para a página de submenu.

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

  • No iOS, a página de detalhes desliza para a direita à medida que a página de submenu desliza da esquerda e a parte esquerda da página de detalhes ainda está visível.
  • No Android, as páginas de detalhes e submenus são sobrepostas umas nas outras.
  • Na UWP, a página de submenu desliza da parte à esquerda da página de detalhes, desde que a FlyoutLayoutBehavior propriedade esteja definida Popovercomo .

Comportamento semelhante será observado no modo paisagem, exceto que a página de submenu no iOS e no 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 de layout da página de detalhes.

Criar um FlyoutPage

Um FlyoutPage contém Flyout as propriedades e Detail que são 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 sempre seja uma ContentPage instância e que a página de detalhes só deve ser preenchida com TabbedPageas instâncias , NavigationPagee ContentPage . 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 como 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 de 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 a página de submenu ou detalhes é apresentada. Ele deve ser definido como true para exibir a página de submenu e para false exibir a página de detalhes.

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

Exemplo de página de detalhes

Controlar o comportamento de layout da página de detalhes

A forma como o FlyoutPage gerencia as páginas de submenu e detalhes depende se o aplicativo está em execução em um telefone ou tablet, a orientação do dispositivo e o 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 de plataforma.
  • Popover – A página de detalhes abrange ou cobre parcialmente a página do submenu.
  • Split – A página de 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 FlyoutLayoutBehavior propriedade afeta apenas os aplicativos em execução em tablets ou na área de trabalho. Aplicativos em execução em telefones sempre têm o Popover comportamento .