Shell do Xamarin.FormsXamarin.Forms Shell

Visualizar

Baixar Exemplo Baixar o exemploDownload Sample Download the sample

O Shell do Xamarin.Forms é um contêiner para aplicativos, que fornece os recursos fundamentais da interface do usuário que a maioria dos aplicativos exige, permitindo que você se concentre na carga de trabalho principal do aplicativo.Xamarin.Forms Shell is a container for applications, that provides fundamental UI features that most applications require, leaving you to focus on the application's core workload. Os aplicativos do Shell são fornecidos com a seguinte funcionalidade:Shell applications are provided with the following functionality:

  • Um único lugar para descrever a estrutura visual de um aplicativo.A single place to describe the visual structure of an application.
  • Uma interface do usuário de navegação comum.A common navigation user interface.
  • Um serviço de navegação com vinculação profunda.A navigation service with deep linking.
  • Um manipulador de pesquisa integrado.An integrated search handler.

Essa funcionalidade reduz a complexidade dos aplicativos e aumenta a produtividade do desenvolvedor.This functionality reduces the complexity of applications, while increasing developer productivity. Além disso, o Shell é gravado considerando a renderização do consumo de memória e de velocidade.In addition, Shell is written with rendering speed and memory consumption in mind.

Importante

Os aplicativos iOS e Android existentes podem adotar o Shell e beneficiar-se imediatamente das melhorias de navegação, desempenho e extensibilidade.Existing iOS and Android applications can adopt Shell and benefit immediately from navigation, performance, and extensibility improvements.

O Shell fornece uma interface do usuário de navegação "pretensiosa", com base em guias e submenus.Shell provides an opinionated navigation user interface, based on flyouts and tabs. O nível superior da navegação em um aplicativo do Shell é um submenu:The top level of navigation in a Shell application is a flyout:

SubmenuFlyout

O próximo nível de navegação é a barra de guias inferior:The next level of navigation is the bottom tab bar:

Guias inferioresBottom tabs

Quando o submenu não estiver aberto, a barra de guias inferior será considerada o nível superior do painel de navegaçãoWhen the flyout isn't open the bottom tab bar will be considered the top level of navigation

Em cada guia inferior, o próximo nível de navegação é a barra de guias superior, em que cada guia é uma ContentPage:Within each bottom tab, the next navigation level is the top tab bar, where each tab is a ContentPage:

Guias superioresTop tabs

Dentro de cada ContentPage, instâncias de ContentPage adicionais podem ser adicionadas e removidas da pilha de navegação.Within each ContentPage, additional ContentPage instances can be added to and removed from the navigation stack.

Inicializando um aplicativo do ShellBootstrapping a Shell application

Um aplicativo do Shell é inicializado definindo a propriedade MainPage da classe App para uma instância de um arquivo Shell:A Shell application is bootstrapped by setting the MainPage property of the App class to an instance of a Shell file:

namespace TailwindTraders.Mobile
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();

            MainPage = new TheShell();
        }
    }
}

A classe TheShell é um arquivo XAML que descreve a estrutura visual do aplicativo.The TheShell class is a XAML file that describes the visual structure of your application.

Importante

O Shell é experimental no momento e só pode ser usado com a adição de Forms.SetFlags("Shell_Experimental"); ao projeto de plataforma, antes da invocação do método Forms.Init.Shell is currently experimental, and can only be used by adding Forms.SetFlags("Shell_Experimental"); to your platform project, prior to invoking the Forms.Init method.

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        global::Xamarin.Forms.Forms.SetFlags("Shell_Experimental");

        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(savedInstanceState);

        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
        LoadApplication(new App());
    }
}

Hierarquia de arquivos do ShellShell file hierarchy

Um arquivo do Shell consiste em três elementos hierárquicos:A Shell file consists of three hierarchical elements:

  • ShellItem.ShellItem. Um ou mais itens no submenu.One or more items in the flyout. Cada ShellItem é um filho de um Shell.Every ShellItem is a child of a Shell.
  • ShellSection.ShellSection. Conteúdo agrupado, navegável pelas guias inferiores.Grouped content, navigable by bottom tabs. Cada ShellSection é um filho de um ShellItem.Every ShellSection is a child of a ShellItem.
  • ShellContent.ShellContent. As instâncias de ContentPage no aplicativo, que são navegáveis pelas guias superiores.The ContentPage instances in your application, which are navigable by top tabs. Cada ShellContent é um filho de uma ShellSection.Every ShellContent is a child of a ShellSection.

Nenhum desses elementos representa uma interface do usuário, mas sim a organização da estrutura visual do aplicativo.None of these elements represent any user interface, but rather the organization of the application's visual structure. O Shell usará esses elementos e produzirá a interface do usuário de navegação do conteúdo.Shell will take these elements and produce the navigation user interface for the content.

O XAML a seguir mostra um exemplo simples de um arquivo Shell:The following XAML shows a simple example of a Shell file:

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:TailwindTraders.Mobile.Features.Shell"
       x:Class="TailwindTraders.Mobile.Features.Shell.TheShell"
       Title="TailwindTraders">
    <ShellItem Title="Home">
        <ShellSection>
            <ShellContent>
                <local:HomePage />
            </ShellContent>
        </ShellSection>
    </ShellItem>
</Shell>

Observação

Cada ShellItem também pode definir uma propriedade FlyoutIcon para um ImageSource, que será exibido à esquerda do título.Each ShellItem can also set an FlyoutIcon property to an ImageSource, which will be displayed to the left of the title.

Esse XAML exibe a HomePage, pois esse é o primeiro item de conteúdo declarado no arquivo do Shell:This XAML displays the HomePage, because it's the first item of content declared in the Shell file:

Home pageHome page

Quando o botão de hambúrguer é pressionado, o menu suspenso é exibido:Pressing the hamburger button displays the flyout:

Submenu abertoFlyout open

O número de itens no submenu pode ser aumentado com a adição de mais instâncias de ShellItem ao arquivo do Shell.The number of items in the flyout can be increased by adding more ShellItem instances to the Shell file. No entanto, observe que HomePage é criado durante a inicialização do aplicativo, e a adição de mais instâncias de ShellItem usando essa abordagem fará com que essas páginas também sejam criadas durante a inicialização do aplicativo.However, note that HomePage is created during application startup, and adding additional ShellItem instances using this approach will result in these pages also being created during application startup. Isso pode ser evitado definindo a propriedade ShellContent.ContentTemplate para um DataTemplate:This can be avoided by setting the ShellContent.ContentTemplate property to a DataTemplate:

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:TailwindTraders.Mobile.Features.Shell"
       x:Class="TailwindTraders.Mobile.Features.Shell.TheShell"
       Title="TailwindTraders">
    <ShellItem Title="Home">
        <ShellSection>
            <ShellContent>
                <local:HomePage />
            </ShellContent>
        </ShellSection>
    <ShellItem>
    <ShellContent Title="Profile"
                  ContentTemplate="{DataTemplate local:ProfilePage}" />
</Shell>

Com essa abordagem, a ProfilePage é criada somente quando o usuário navega para ela e não na inicialização do aplicativo.With this approach, ProfilePage is only created when the user navigates to it, rather than at application startup. Além disso, observe que para a ProfilePage, os objetos ShellItem e ShellSection são omitidos, e a propriedade Title é definida na instância de ShellContent.In addition, note that for ProfilePage, the ShellItem and ShellSection objects are omitted, with the Title property being defined on the ShellContent instance. Essa abordagem concisa requer menos marcação com o Shell fornecendo os wrappers lógicos necessários (sem introduzir exibições adicionais à árvore visual).This concise approach requires less markup, with Shell supplying the required logical wrappers (without introducing additional views to the visual tree).

Além disso, a aparência de cada ShellItem pode ser personalizada definindo a propriedade Shell.ItemTemplate para um DataTemplate:In addition, each ShellItem appearance can be customized by setting the Shell.ItemTemplate property to a DataTemplate:

<Shell.ItemTemplate>
    <DataTemplate>
        <ContentView HeightRequest="32">
            <ContentView.Padding>
                <Thickness Left="32"
                           Top="16" />
            </ContentView.Padding>
            <Label Text="{Binding Title}" />
        </ContentView>
    </DataTemplate>
</Shell.ItemTemplate>          

Esse código simplesmente reposiciona o texto para cada ShellItem dentro do submenu.This code simply repositions the text for each ShellItem within the flyout. Observe que o Shell fornece as propriedades Title (e Icon) para o BindingContext do DataTemplate.Note that Shell provides the Title (and Icon) properties to the BindingContext of the DataTemplate.

SubmenuFlyout

O submenu é o menu raiz do aplicativo e consiste em um cabeçalho de submenu e em itens de menu:The flyout is the root menu for the application, and consists of a flyout header, and menu items:

Submenu anotadoAnnotated flyout

Comportamento do submenuFlyout behavior

O submenu por ser acessado pelo botão de hambúrguer ou passando o dedo na lateral tela.The flyout is accessible through the hamburger button or by swiping from the side of the screen. No entanto, esse comportamento pode ser alterado definindo a propriedade Shell.FlyoutBehavior para um dos membros da enumeração FlyoutBehavior:However, this behavior can be changed by setting the Shell.FlyoutBehavior property to one of the FlyoutBehavior enumeration members:

<Shell ...
       FlyoutBehavior="Disabled">
    ...
</Shell>

A definição da propriedade FlyoutBehavior para Disabled oculta o submenu, o que é útil quando há apenas um ShellItem.Setting the FlyoutBehavior property to Disabled hides the flyout, which is useful when you only have one ShellItem. Outros valores válidos de FlyoutBehavior são Flyout (padrão) e Locked.The other valid FlyoutBehavior values are Flyout (default), and Locked.

Cabeçalho do submenuFlyout header

O cabeçalho do submenu é o conteúdo que é exibido, opcionalmente, na parte superior do submenu, com sua aparência definida por uma View que pode ser configurada por meio do valor da propriedade Shell.FlyoutHeader:The flyout header is the content that optionally appears at the top of the flyout, with its appearance being defined by a View that can be set through the Shell.FlyoutHeader property value:

<Shell.FlyoutHeader>
    <local:FlyoutHeader />
</Shell.FlyoutHeader>

Como alternativa, a aparência do cabeçalho do submenu pode ser definida configurando a propriedade Shell.FlyoutHeaderTemplate para um DataTemplate:Alternatively, the flyout header appearance can be defined by setting the Shell.FlyoutHeaderTemplate property to a DataTemplate:

<Shell.FlyoutHeaderTemplate>
    <DataTemplate>
        <StackLayout HorizontalOptions="Fill"
                     VerticalOptions="Fill"
                     BackgroundColor="White"
                     Padding="16">
            <Label FontSize="Medium"
                   Text="Smart Shopping">
                <Label.Margin>
                    <Thickness Left="8" />
                </Label.Margin>
            </Label>
            <Button Image="photo"
                    Text="By taking a photo">
                <Button.Margin>
                    <Thickness Top="16" />
                </Button.Margin>
            </Button>
            <Button Image="ia"
                    Text="By using AR">
                <Button.Margin>
                    <Thickness Top="8" />
                </Button.Margin>
            </Button>
        </StackLayout>
    </DataTemplate>
</Shell.FlyoutHeaderTemplate>

Esse XAML resulta no cabeçalho de submenu a seguir:This XAML results in the following flyout header:

Cabeçalho do submenuFlyout header

Por padrão, o cabeçalho do submenu ficará fixo no submenu enquanto o conteúdo abaixo poderá ser rolado se houver itens suficientes.By default, the flyout header will be fixed in the flyout while the content below will scroll if there are enough items. No entanto, esse comportamento pode ser alterado definindo a propriedade Shell.FlyoutHeaderBehavior para um dos membros da enumeração FlyoutHeaderBehavior:However, this behavior can be changed by setting the Shell.FlyoutHeaderBehavior property to one of the FlyoutHeaderBehavior enumeration members:

<Shell ...
       FlyoutHeaderBehavior="CollapseOnScroll">
    ...
</Shell>

A definição do FlyoutHeaderBehavior para CollapseOnScroll recolhe o submenu conforme a rolagem ocorre.Setting the FlyoutHeaderBehavior to CollapseOnScroll collapses the flyout as scrolling occurs. Os outros valores válidos de FlyoutHeaderBehavior são Default, Fixed e Scroll (rolar com os itens de menu).The other valid FlyoutHeaderBehavior values are Default, Fixed, and Scroll (scroll with the menu items).

O número de itens no submenu pode ser aumentado adicionando mais instâncias de ShellItem.The number of items in the flyout can be increased by adding more ShellItem instances. No entanto, também é possível adicionar instâncias de MenuItem no menu suspenso.However, it's also possible to add MenuItem instances to the flyout. Isso permite cenários como a navegação até uma página idêntica passando dados por meio da propriedade MenuItem.CommandParameter.This permits scenarios such as navigating to an identical page while passing data through the MenuItem.CommandParameter property.

As instâncias de MenuItem devem ser adicionadas à coleção Shell.MenuItems:MenuItem instances should be added to the Shell.MenuItems collection:

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:TailwindTraders.Views"
       x:Class="TailwindTraders.Shell"
       FlyoutHeaderBehavior="Fixed"
       Title="Tailwind Traders"
       ...>
    <Shell.MenuItems>
        <MenuItem Command="{Binding ProductTypeCommand}"
                  CommandParameter="1"
                  Text="Holiday decorations" />
        <MenuItem Command="{Binding ProductTypeCommand}"
                  CommandParameter="2"
                  Text="Appliances" />
        <MenuItem Command="{Binding ProductTypeCommand}"
                  CommandParameter="3"
                  Text="Bathrooms" />
        ...
    </Shell.MenuItems>
    <ShellItem Title="Home">
        <ShellSection>
            <ShellContent>
                <local:HomePage />
            </ShellContent>
        </ShellSection>
    </ShellItem>    
</Shell>

Observação

Cada MenuItem também pode definir uma propriedade Icon para uma FileImageSource, que será exibida à esquerda do texto.Each MenuItem can also set an Icon property to a FileImageSource, which will be displayed to the left of the text.

Esse XAML resulta no submenu a seguir:This XAML results in the following flyout:

Submenu completoFull flyout

Além disso, a aparência do MenuItem pode ser personalizada definindo a propriedade Shell.MenuItemTemplate para um DataTemplate:In addition, MenuItem appearance can be customized by setting the Shell.MenuItemTemplate property to a DataTemplate:

<Shell.MenuItemTemplate>
    <DataTemplate>
        <ContentView HeightRequest="32">
            <ContentView.Padding>
                <Thickness Left="32"
                           Top="16" />
            </ContentView.Padding>
            <Label Text="{Binding Text}"
                   FontAttributes="Bold" />
        </ContentView>
    </DataTemplate>
</Shell.MenuItemTemplate>

Isso resulta em instâncias de MenuItem com o texto renderizado em negrito:This results in MenuItem instances having their text rendered in bold:

Itens de menu em negritoBold menu items

TabulaçõesTabs

As instâncias de ShellSection serão renderizadas como guias inferiores, desde que haja várias instâncias de ShellSection em um único ShellItem:ShellSection instances will be rendered as bottom tabs, provided that there are multiple ShellSection instances in a single ShellItem:

<ShellItem Title="Bottom Tab Sample"
           Style="{StaticResource BaseStyle}">
    <ShellSection Title="AR" Icon="ia.png">
        <ShellContent ContentTemplate="{DataTemplate local:ARPage}"/>
    </ShellSection>
    <ShellSection Title="Photo" Icon="photo.png">
        <ShellContent ContentTemplate="{DataTemplate local:PhotoPage}"/>
    </ShellSection>
</ShellItem>

Neste exemplo, as instâncias de ShellSection serão renderizadas como guias inferiores:In this example, the ShellSection instances will be rendered as bottom tabs:

Guias inferioresBottom tabs

Os itens ShellContent serão renderizados como guias superiores, desde que haja várias instâncias de ShellContent em uma única ShellSection:ShellContent items will be rendered as top tabs, provided that there are multiple ShellContent instances within a single ShellSection:

<ShellItem Title="Store Home"
           Shell.TitleView="Store Home"
           Style="{StaticResource BaseStyle}">
    <ShellSection Title="Browse Product">
        <ShellContent Title="Featured"
                      ContentTemplate="{DataTemplate local:FeaturedPage}" />
        <ShellContent Title="On Sale"
                      ContentTemplate="{DataTemplate local:SalePage}" />
    </ShellSection>
</ShellItem>

Neste exemplo, as instâncias de ShellContent serão renderizadas como guias superiores:In this example, the ShellContent instances will be rendered as top tabs:

Guias superioresTop tabs

As guias podem ser estilizadas usando estilos XAML ou fornecendo um renderizador personalizado.Tabs can be styled using XAML styles, or by supplying a custom renderer. Por exemplo, o exemplo a seguir mostra um estilo XAML que define a cor da guia:For example, the following example shows a XAML style that sets tab color:

<Style x:Key="BaseStyle"
       TargetType="Element">
    <Setter Property="Shell.ShellTabBarBackgroundColor"
            Value="#3498DB" />
    <Setter Property="Shell.ShellTabBarTitleColor"
            Value="White" />
    <Setter Property="Shell.ShellTabBarUnselectedColor"
            Value="#B4FFFFFF" />
</Style>

O Shell inclui uma experiência de navegação baseada em URI.Shell includes a URI-based navigation experience. Os URIs fornecem uma experiência de navegação aprimorada que permite a navegação para qualquer página no aplicativo, sem precisar seguir uma hierarquia de navegação definida.URIs provide an improved navigation experience that permits navigation to any page in the application, without having to follow a set navigation hierarchy. Além disso, eles também oferecem a capacidade de navegar para trás, sem precisar visitar todas as páginas na pilha de navegação.In addition, it also provides the ability to navigate backwards without having to visit all of the pages on the navigation stack.

Essa navegação baseada em URI é realizada com rotas, que são segmentos de URI usados para navegar dentro do aplicativo.This URI-based navigation is accomplished with routes, which are URI segments used to navigate within the application. O arquivo Shell deve declarar um esquema de rota, um host de rota e uma rota:The Shell file must declare a route scheme, a route host, and a route:

<Shell ...
       Route="tailwindtraders"
       RouteHost="www.microsoft.com"
       RouteScheme="app">
    ...
</Shell>

Combinados, os valores de propriedade RouteScheme, RouteHost e Route formam o URI raiz de app://www.microsoft.com/tailwindtraders.Combined, the RouteScheme, RouteHost, and Route property values form the app://www.microsoft.com/tailwindtraders root URI.

Cada elemento no arquivo Shell também pode definir uma propriedade de rota que pode ser usada na navegação programática.Each element in the Shell file can also define a route property that can be used in programmatic navigation.

No construtor do arquivo Shell ou em qualquer outro local que seja executado antes da invocação de uma rota, é possível registrar explicitamente rotas adicionais para todas as páginas que não sejam representadas por um elemento do Shell (como instâncias de MenuItem):In the Shell file constructor, or any other location that runs before a route is invoked, additional routes can be explicitly registered for any pages that aren't represented by a Shell element (such as MenuItem instances):

Routing.RegisterRoute("productcategory", typeof(ProductCategoryPage));

Implementando a navegaçãoImplementing navigation

Os itens de menu expõem uma propriedade Command que pode ser usada para implementar a navegação:Menu items expose a Command property that can be used to implement navigation:

public ICommand ProductTypeCommand { get; } = new Command<string>(NavigateToProductType);

static void NavigateToProductType(string typeId)
{
  (App.Current.MainPage as Xamarin.Forms.Shell).GoToAsync($"app://tailwindtraders/productcategory?id={typeId}", true);
}

Para invocar a navegação, é necessário obter uma referência ao aplicativo Shell por meio da propriedade MainPage da classe Application.To invoke navigation, a reference to the application Shell, through the MainPage property of the Application class, must be obtained. Em seguida, a navegação poderá ser invocada ao chamar o método GoToAsync passando um URI válido como um argumento.Then, navigation can be invoked by calling the GoToAsync method, passing a valid URI as an argument. O método GoToAsync navega usando um objeto ShellNavigationState, que será construído usando uma string ou um Uri.The GoToAsync method navigates using a ShellNavigationState object, which will be constructed from a string or a Uri.

Passando dadosPassing data

Os dados podem ser passados entre as páginas por meio de parâmetros de cadeia de consulta.Data can be passed between pages through query string parameters. O Shell definirá os valores dos parâmetros de cadeia de consulta na ContentPage ou no ViewModel quando você adicionar atributos de propriedade de consulta à classe:Shell will set the query string parameter values on the ContentPage or ViewModel when you add query property attributes to the class:

[QueryProperty("TypeID", "id")]
public partial class ProductCategoryPage : ContentPage
{
    private string _typeId;

    public ProductCategoryPage()
    {
        InitializeComponent();

        BindingContext = new ProductCategoryViewModel();
    }

    public string TypeID
    {
        get => _typeId;
        set => MyLabel.Text = value;
    }
}

O atributo QueryProperty especifica que o TypeID receberá os dados passados no parâmetro de cadeia de consulta id do URI na chamada de método GoToAsync.The QueryProperty attribute specifies that the TypeID will receive the data passed in the id query string parameter from the URI in the GoToAsync method call.

Interceptando a navegaçãoIntercepting navigation

O Shell fornece a capacidade de interceptar o roteamento de navegação antes que ele seja concluído e após sua conclusão.Shell provides the ability to hook into the navigation routing before it has completed, and after it has completed. Isso pode ser feito registrando manipuladores de eventos para os eventos Navigating e Navigated, respectivamente:This can be accomplished by registering events handlers for the Navigating and Navigated events, respectively:

<Shell ...
       Navigating="OnShellNavigating">
    ...
</Shell>
void OnShellNavigating(object sender, ShellNavigatingEventArgs e)
{
  if (...)
  {
    e.Cancel(); // Cancel the navigation
  }
}

A classe ShellNavigatingEventArgs fornece as seguintes propriedades:The ShellNavigatingEventArgs class provides the following properties:

PropriedadeProperty TipoType DescriçãoDescription
AtualCurrent ShellNavigationState O URI da página atual.The URI of the current page.
OrigemSource ShellNavigationState O URI que representa onde a navegação foi originada.The URI representing where the navigation originated.
DestinoTarget ShellNavigationSource O URI que representa para onde a navegação se destina.The URI representing where the navigation is destined.
CanCancelCanCancel bool Um valor que indica se é possível cancelar a navegação.A value indicating if it's possible to cancel the navigation.
CanceladaCancelled bool Um valor que indica se a navegação foi cancelada.A value indicating if the navigation was cancelled.

Além disso, a classe ShellNavigatingEventArgs fornece um método Cancel.In addition, the ShellNavigatingEventArgs class provides a Cancel method.

A classe ShellNavigatedEventArgs fornece as seguintes propriedades:The ShellNavigatedEventArgs class provides the following properties:

PropriedadeProperty TipoType DescriçãoDescription
AtualCurrent ShellNavigationState O URI da página atual.The URI of the current page.
VoltarPrevious ShellNavigationState O URI da página anterior.The URI of the previous page.
OrigemSource ShellNavigationSource O URI que representa onde a navegação foi originada.The URI representing where the navigation originated.

Além disso, o Shell fornece um método OnBackButtonPressed substituível que pode ser usado para interceptar um pressionamento do botão de retorno.In addition, Shell provides an overridable OnBackButtonPressed method that can be used to intercept a back button press.