Edição especial do Connect(); 2018

Volume 33 – Número 13

Desenvolvimento entre plataformas - Introdução ao Shell do Xamarin.Forms

De David Ortinau; 2018

O Xamarin.Forms é um kit de ferramentas especializado para desenvolvedores de plataforma cruzada que adoram XAML e C#, porque maximiza o compartilhamento de código e também fornece acesso total a todas as APIs de plataforma nativa e controles de interface do usuário. Esse recurso contém tecnologias e conceitos que podem ser entusiasmantes, mas confusos, quando você está começando. Na verdade, alguns desenvolvedores acham o recurso frustrante desde o início. Você optou pelo Xamarin para ser produtivo e a última coisa que você quer encontrar é um problema indesejado. Este ano, no Connect();, temos a satisfação de apresentar o Shell do Xamarin.Forms, um novo ponto de partida padrão para o desenvolvimento de aplicativos móveis que reduz a complexidade e aumenta a produtividade.

Como o nome sugere, o Shell é basicamente um contêiner que cuida dos recursos básicos da interface do usuário necessários ao seu aplicativo para que você possa se concentrar no trabalho principal de seu aplicativo. Os aplicativos iOS e Android existentes também podem facilmente adotar o Shell e se beneficiarem imediatamente das melhorias na navegação, desempenho da interface do usuário e extensibilidade. O Shell oferece os seguintes benefícios:

  • Um único lugar para descrever a estrutura visual de aplicativos
  • Uma interface comum de navegação e serviço de navegação onipresente com links diretos
  • Um manipulador de pesquisa integrado para melhorar a experiência geral de pesquisa no aplicativo
  • Uma filosofia extensível por padrão para oferecer mais flexibilidade e versatilidade

O aplicativo

No início de cada projeto, a estrutura do aplicativo é esboçada para você possa criá-la (e esperamos que o plano não fique apenas no pensamento). Às vezes, ele é fornecido em uma composição de design ou escrito em papel. A Shell facilita muito a aceitação desse conteúdo e sua transformação em um contêiner de aplicativos em execução, preparado para quem quiser preenchê-lo com conteúdo e funcionalidade.

Neste artigo, vou usar o exemplo de um aplicativo móvel de compra chamado Traders Tailwind. Este é um novo aplicativo de referência que a equipe criou para demonstrar como você pode usar o Shell do Xamarin.Forms, o Azure, os Serviços Cognitivos e vários outros recursos e serviços. Na Figura 1, observe as composições de design fornecidas pela nossa incrível equipe de design.

Componentes de design do aplicativo de exemplo do Tailwind Traders
Figura 1 - Componentes de design do aplicativo de exemplo do Tailwind Traders

Como você pode ver nas telas exibidas, o aplicativo fornece toda a funcionalidade óbvia necessária, incluindo logon e o fluxo de registro, uma experiência de navegação com categorias de produtos e pesquisa e um fluxo de check-out. Este aplicativo também aproveita a câmera do dispositivo e o poder da API da Visão Personalizada do Azure para identificar produtos em tempo real.

O início rápido

Vamos rapidamente desenvolver esse aplicativo usando o Shell. Abra o Visual Studio 2019 e inicie um novo aplicativo de plataforma cruzada com o Xamarin.Forms. Para efeitos deste artigo e para entender o poder do Shell, vamos começar com um projeto em branco e criar a estrutura do aplicativo da Tailwind Traders.

Depois que os arquivos do projeto forem gerados, abra o App.xaml.cs e observe que MainPage está configurado para uma nova instância do Shell. (Você pode fazer o download dos modelos do Shell em aka.ms/xf-shell-templates.) Estruturalmente, essa é a única diferença em relação a um aplicativo típico do Xamarin.Forms que você possa ter visto no passado. Eis o código:

namespace TailwindTraders.Mobile
{
  public partial class App
  {
    public App()
    {
      InitializeComponent();
      MainPage = new AppShell();
    }
  }
}

Abra o AppShell.xaml na raiz de seu projeto de biblioteca .NET Standard, conforme mostrado na Figura 2.

Figura 2 Uma única página Shell.xaml

<?xml version="1.0" encoding="UTF-8"?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:TailwindTraders"
       RouteHost="tailwindtraders.com"
       RouteScheme="app"
       FlyoutBehavior="Disabled"
       Title="TailwindTraders"
       x:Class=" TailwindTraders.AppShell">
  <ShellItem>
    <ShellSection>
      <ShellContent>
        <local:MainPage/>
      </ShellContent>
    </ShellSection>
  <ShellItem>
</Shell>

Vamos dividir este arquivo em partes. Um Shell é formado por três elementos hierárquicos: ShellItems, ShellSections e ShellContent. Cada ShellContent é filho de um ShellSection, que é filho de um ShellItem - todas as partes do Shell. Nenhum deles representa a interface do usuário, mas sim a organização da arquitetura de seu aplicativo. O Shell usa esses itens e produz a navegação da interface do usuário apropriada para a plataforma na qual ele está em execução:

  • ShellItem: A estrutura de nível superior do aplicativo representada por um item no submenu. Pode conter vários ShellSections.
  • ShellSection: Um agrupamento do conteúdo do aplicativo, navegável pelas guias inferiores. Pode conter um ou mais ShellContents com vários ShellContents navegáveis pelas guias superiores.
  • ShellContent: O ContentPages de seu aplicativo.

Posso usar esses três elementos para descrever a estrutura visual do aplicativo móvel da Tailwind Traders. Ignorando o fluxo de logon e registro, adicionarei vários ShellItems para hospedar o conteúdo, representado por um menu do submenu à esquerda.

Por que não usar nomes como FlyoutItem, BottomTab, TopTab para conceitos do Shell? Nossa equipe na Microsoft teve muitas discussões sobre isso e acha que o Xamarin.Forms satisfaz as necessidades de plataformas conhecidas e futuras que, às vezes, não compartilham os conceitos exatos de guias ou menus. Mantendo o resumo da nomenclatura, permitimos que você decida por estilo e modelos se esses elementos deverão ser representados de forma consistente em plataformas divergentes ou se devem aderir à estética de design de cada plataforma. E, claro, seus comentários são sempre bem-vindos nessas ocasiões!

A Figura 3 oferece um exemplo. Aqui você vê um menu no submenu (os dois terços inferiores da interface do usuário), que é preenchido automaticamente pelos ShellItems. Isso permite que você navegue para as diferentes áreas de seu aplicativo. Além desses itens, você pode adicionar itens de menu que não estão associados a um item do Shell. O cabeçalho de submenu na parte superior (os dois botões) apresenta um conteúdo especial que consiste em qualquer coisa que você queira apresentar nesse espaço. Para declarar um FlyoutHeader personalizado dentro do Shell.xaml, use este código:

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

Elementos do FlyoutMenu
Figura 3 - Elementos do FlyoutMenu

O elemento de cabeçalho permite que você controle como ele se comporta quando os usuários rolam a exibição. Há três opções:

  • Fixed: O cabeçalho permanece fixo enquanto o conteúdo é rolado.
  • Scroll: Rola com os itens do menu.
  • CollapseOnScroll: Recolhe de forma paralaxe à medida que você rola.

Para ajustar esse comportamento, defina a propriedade FlyoutHeaderBehavior em seu Shell com o valor desejado que foi anteriormente detalhado. Por enquanto, vamos mantê-lo corrigido com o seguinte código:

<Shell
  x:Class="TailwindTraders.Mobile.Features.Shell.Shell"
  FlyoutHeaderBehavior="Fixed"  
  ...            
  >             
  ...            
</Shell>

Em seguida, vamos configurar o conteúdo. Olhando para o design, vejo que há uma tela inicial, uma série de categorias de produtos, um perfil e, finalmente, uma tela de logout. Vamos começar com a tela inicial, com o código XAML a seguir:

<ShellItem Title="Home">
  <ShellSection>
    <ShellContent>
      <local:HomePage />
    </ShellContent>
  </ShellSection>
</ShellItem>

Ao decompor esse XAML de dentro para fora, adicionei a HomePage ao aplicativo, que será a primeira ContentPage a ser lançada por ser o primeiro conteúdo declarado no arquivo do shell. Esse é o mesmo tipo de ContentPage que você usa em seus aplicativos Xamarin.Forms existentes, agora hospedados em um contexto do Shell.

Para este projeto, eu só preciso definir um título, mas o ShellItem também fornece a propriedade FlyoutIcon que permite fornecer uma imagem para ser exibida à esquerda do item. Os ícones podem ser qualquer ImageSource do Xamarin.Forms.

Vamos continuar e executar o aplicativo. Na home page, clique no ícone de hambúrguer para abrir o menu do submenu. Tocar nesse item de menu leva você para a tela inicial (que é atualmente a única tela). Vamos começar a trabalhar adicionando mais elementos.

Em seguida, implementarei as categorias de produtos, como "Decorações de Natal", "Eletrodomésticos" e afins. Eu poderia adicionar ShellItems a cada um delas, mas, como as páginas da categoria do produto são todas a mesma página com conteúdo diferente, posso tirar vantagem disso. Usarei um MenuItem simples para navegar para a mesma página e passar dados usando o CommandParameter para evitar a duplicação desnecessária de páginas. Este é o código para adicionar um MenuItem no Shell.xaml:

<Shell.MenuItems>
  <MenuItem
    Command="{Binding ProductTypeCommand}"
    CommandParameter="1"
    Text="Holiday decorations" />
</Shell.MenuItems>

Um ótimo recurso do Shell é que ele é compatível com a associação de dados. Neste caso, tenho um "Command" em um modelo de exibição que pode executar a navegação. Assim como os ShellItems, os MenuItems usam texto e um ícone. Além disso, assim como os ShellItems, posso fornecer um estilo ou até um modelo personalizado para personalizar ainda mais o design, definindo a propriedade MenuItemTemplate no Shell.

Posso adicionar mais itens de menu a cada categoria para concluir a tarefa. A Figura 4 mostra o código para todos os itens do menu, enquanto a Figura 5 mostra o resultado visual no menu do submenu do aplicativo.

Figura 4 Todos os itens do menu

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
  x:Class="TailwindTraders.AppShell"
  FlyoutHeaderBehavior="Fixed"
  xmlns="http://xamarin.com/schemas/2014/forms"
  xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
  xmlns:local="clr-namespace:TailwindTraders.Views"
  Title="Tailwind Traders"
  x:Name="theShell"
  Route="tailwindtraders"
  RouteHost="microsoft.com"
  RouteScheme="app">
  <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" />
    <MenuItem
      Command="{Binding ProductTypeCommand}"
      CommandParameter="4"
      Text="Doors &amp; Windows" />
    <MenuItem
      Command="{Binding ProductTypeCommand}"
      CommandParameter="5"
      Text="Flooring" />
    <MenuItem
      Command="{Binding ProductTypeCommand}"
      CommandParameter="6"
      Text="Kitchen" />
    <MenuItem
      Command="{Binding ProductTypeCommand}"
      CommandParameter="7"
      Text="Storage" />
  </Shell.MenuItems>
  <ShellItem Title="Home">
    <ShellSection>
      <ShellContent>
        <local:HomePage />
      </ShellContent>
    </ShellSection>
  </ShellItem>
</Shell>

Submenu com todos os itens do menu
Figura 5 Submenu com todos os itens do menu

Como adicionar mais páginas

Agora vamos adicionar a página Perfil do design para nosso aplicativo. Adicione um novo ContentPage ao projeto e, em seguida, volte para o arquivo Shell.xaml. Você poderia copiar o XAML (mostrado na Figura 4) usado na HomePage e apenas substituí-lo pela página Perfil, mas você arriscaria atrasar o aplicativo porque HomePage é criada imediatamente durante a inicialização do aplicativo. Para evitar que todas as páginas do aplicativo sejam carregadas de uma vez, uso um modelo de dados da seguinte forma:

<ShellContent
  Title="Profile"
  ContentTemplate="{DataTemplate local:ProfilePage}" />

Em vez de fornecer a ContentPage diretamente para a propriedade de conteúdo do ShellContent, forneço um modelo de dados. Quando o usuário navega para uma tela, o Shell instancia a página solicitada dinamicamente.

Uma coisa a ser observada com esse tratamento em comparação com a HomePage é que omiti os wrappers ShellItem e ShellSection e coloquei o título diretamente no ShellContent. Isso é muito menos detalhado e o Shell sabe como lidar com isso fornecendo os wrappers lógicos necessários. Também é importante observar que esses wrappers não introduzem visualizações da interface do usuário à árvore. O shell é gravado tendo em mente a velocidade de renderização e o consumo de memória. O resultado disso é que o impacto no desempenho do sistema operacional do Android é mantido baixo ao hospedar o mesmo conteúdo e interface do usuário que você tem atualmente nesse novo contexto do Shell. Claro, você ainda é responsável por arquitetar os componentes internos de seus aplicativos, mas a Shell oferece um ótimo ponto de partida.

Como definir o estilo do submenu

Você pode estilizar aspectos do Shell e do FlyoutMenu como faria com qualquer outro elemento XAML usando o estilo CSS ou XAML. E se você quiser ir mais longe com a exibição do item de menu do submenu? Olhando novamente para o design na Figura 3, os itens do menu são mais ousados do que os outros itens do shell.

A exibição de itens de menu e itens do shell é extensível, fornecendo um DataTemplate ao Shell. Um MenuItem é processado no menu de submenu usando o MenuItemTemplate do Shell e um ShellItem é processado usando um ItemTemplate. Para ter controle total sobre a aparência deles, defina cada propriedade como um DataTemplate contendo um ContentView personalizado. O Shell fornecerá as propriedades associáveis Title e Icon ao modelo BindingContext, conforme mostrado na Figura 6. Você pode conferir o resultado visual na Figura 7.

Figura 6 - Como personalizar o Modelo de Item para ShellItems em Shell.xaml

<Shell.ItemTemplate>
  <DataTemplate>
    <ContentView HeightRequest="32">
      <ContentView.Padding>
        <Thickness
          Left="32"
          Top="16" />
      </ContentView.Padding>
      <Label Text="{Binding Title}" />
    </ContentView>
  </DataTemplate>
</Shell.ItemTemplate>
<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>

Imagens dos resultados do Modelo de Item do submenu
Figura 7 Imagens dos resultados do Modelo de Item do submenu

Além de personalizar os renderizadores de itens, vamos adicionar um cabeçalho bonito ao submenu que inclui uma caixa com um rótulo e dois botões para acesso rápido aos recursos da câmera. Como acontece com os outros modelos, adicione um ao FlyoutHeaderTemplate no arquivo Shell.xaml. O conteúdo pode ser qualquer ContentView, portanto, use um StackLayout para posicionar verticalmente os controles filho, conforme mostrado no código na Figura 8. Adicione um pouco de estilo para aproximá-lo da composição de design e execute o aplicativo para ver o resultado, conforme mostrado na Figura 9. Você pode definir FlyoutHeaderBehavior no elemento do Shell para determinar se o cabeçalho será fixo ou se poderá ser rolado ou recolhido quando o usuário rolar a tela.

Figura 8 FlyoutHeaderTemplate

<Shell.FlyoutHeaderTemplate>
  <DataTemplate>
    <StackLayout HorizontalOptions="Fill" VerticalOptions="Fill"
      BackgroundColor="White" Padding="16">
      <StackLayout.Resources>
        <Style TargetType="Button">
          <Setter Property="BackgroundColor" Value="White" />
          <Setter Property="BorderColor" Value="#2F4B66" />
          <Setter Property="BorderWidth">2</Setter>
          <Setter Property="CornerRadius">28</Setter>
          <Setter Property="HeightRequest">56</Setter>
          <Setter Property="Padding">
            <Thickness
              Left="24"
              Right="24" />
           </Setter>
         </Style>
       </StackLayout.Resources>
       <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>

Imagem do submenu com cabeçalho
Figura 9 - Imagem do submenu com cabeçalho

Agora é hora de implementar o comando que navega até as páginas do item de menu. Para fazer isso, usarei o novo roteamento baseado em URI que o Shell introduz. Os URIs permitem que os usuários saltem instantaneamente para qualquer parte do aplicativo e até oferecem a capacidade de retroceder sem precisar criar todas as páginas entre os dois pontos. Vejamos como isso é feito.

Primeiro, preciso declarar as rotas, começando pelo esquema e pelo host do aplicativo, da seguinte maneira:

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

Ao reunir essas partes em um URL, tenho o seguinte URI: app://www.microsoft.com/tailwindtraders.

Cada elemento do Shell definido no arquivo do Shell também usa uma propriedade de rota que posso usar posteriormente para navegar programaticamente. Para páginas que não são representadas por um elemento do Shell, posso registrar uma rota explicitamente. Isso é o que farei aos itens de menu adicionados ao submenu. Cada um deles navegará para uma ProductCategoryPage, uma página que exibe uma lista de produtos para uma categoria específica. Veja o código de registro de rota:

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

Agora posso declarar as rotas necessárias no construtor do Shell.cs ou em qualquer lugar em que ele é executado antes que as rotas sejam chamadas. Os itens de menu expõem um comando para implementar a navegação necessária, como você pode ver neste código:

public ICommand ProductTypeCommand { get; } =
  new Command<string>(NavigateToProductType);
private static void NavigateToProductType(string typeId)
  {
    (App.Current.MainPage as Xamarin.Forms.Shell).GoToAsync(
      $"app:///tailwindtraders/productcategory?id={typeId}", true);
  }

Outra ótima vantagem do Shell é que ele tem métodos estáticos de navegação que podem ser acessados de qualquer lugar no aplicativo. Já se foram os dias em que era preciso se preocupar se o serviço de navegação estaria disponível, passando-o de modo de exibição em modo de exibição para ver modelos e adicionando páginas de navegação para encapsular tudo. Agora, você pode pegar uma referência para o aplicativo do Shell, que é a MainPage de seu aplicativo, acessível como uma propriedade de App.Current. Você pode ver isso no trecho de código anterior. Para executar a navegação, chame o método GoToAsync, passando uma URL válida como um ShellNavigationState. Um ShellNavigationState pode ser construído a partir de uma cadeia de caracteres ou um URI. Observe o código novamente e verá que GoToAsync também permite que você forneça apenas uma cadeia de caracteres e o Shell trabalhará para instanciar um ShellNavigationState.

Os dados podem ser transmitidos entre visualizações e modelos de exibição com parâmetros querystring. O Shell configurará esses valores diretamente em ContentPage ou ViewModel quando você decorar as propriedades apropriadas com os atributos da propriedade de consulta, conforme mostrado na Figura 10.

Figura 10 Exemplo de Atributo de Consulta

[Preserve]
[QueryProperty("TypeID", "id")]
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ProductCategoryPage : ContentPage
{
  private string _typeId;
  public ProductCategoryPage()
  {
    InitializeComponent();
    BindingContext = new ProductCategoryViewModel();
  }
  public string TypeID
  {
    get => _typeId;
    set => MyLabel.Text = value;
  }
}

A QueryProperty usa o nome da propriedade pública (“TypeID” neste exemplo) de sua classe de recebimento e o nome do parâmetro da querystring (“id” neste exemplo) usado na URL.

Interceptação da Ação de Reversão

Interceptar a ação de reversão é um requisito comum no desenvolvimento de aplicativos móveis e isso pode ser um desafio com o Xamarin.Forms. Para solucionar esse problema, o Shell permite que você se conecte ao roteamento de navegação antes e depois de sua conclusão para implementar uma grande variedade de necessidades personalizadas. Veja um exemplo de tratamento de navegação, primeiro com o código XAML atribuindo um manipulador de eventos:

<Shell           ...
  Navigating="Shell_Navigating"

E, em seguida, o código C# do manipulador de eventos:

private void Shell_Navigating(object sender, ShellNavigatingEventArgs e)
{
  if (// Some Boolean evaluation)
  {
    e.Cancel(); // Do not allow this navigation AND/OR do something else
  }
}

Em uma instância do Shell, adicione um manipulador de eventos ao evento Navigating. Em seu codebehind, o ShellNavigatingEventArgs fornece os detalhes básicos da navegação, conforme mostrado na Figura 11.

Figura 11 ShellNavigatingEventArgs

Elemento Tipo Descrição
Atual ShellNavigationState O URI da página atual.
Fonte ShellNavigatinState O URI que representa o local onde a navegação foi originada.
Destino ShellNavigationState O URI que representa a navegação destinada.
CanCancel Boolean Propriedade que indica se é possível cancelar a navegação.
Cancelar Boolean Método para cancelar a navegação solicitada.
Cancelado Boolean Propriedade que indica se a navegação atual foi cancelada.

Guias, guias, guias por todo lado

O menu do submenu é um padrão popular da interface do usuário para navegação. À medida que você pensa na hierarquia de conteúdo em seu aplicativo, o nível superior ou mais externo da navegação é o menu de submenu. A partir daí, a guia inferior será o próximo nível de detalhe. Se você não tiver um submenu, as guias inferiores geralmente serão consideradas o nível mais alto de navegação em um aplicativo. Em seguida, nas guias inferiores, o próximo nível de navegação seria as guias superiores. Além disso, você conhece tudo sobre páginas únicas que enviam por push de uma para outra. Essa é uma abordagem opinativa que o Shell usa para fornecer a interface do usuário de navegação.

Vamos começar pelas guias inferiores. Cada ShellSection dentro de um único ShellItem pode ser representado como uma guia inferior quando mais de uma está presente. Veja um exemplo de código XAML que produz guias inferiores para um aplicativo:

<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>

Esse código apresenta dois ShellSections em um único ShellItem. Essas ShellSections são representadas na interface do usuário como guias na parte inferior da tela. E quando você não precisar do submenu? Quando há apenas um ShellItem, ele pode ser totalmente ocultado ao definir o FlyoutBehavior como Disabled. Para estilizar as guias, use as opções de estilo existentes ou forneça um renderizador personalizado. Ao contrário dos itens do menu de submenu que podem ser modelos de dados personalizados, as guias são muito mais específicas da plataforma. Para adicionar estilo à cor das guias, use as propriedades de estilo da classe do Shell em itens TabBar, da seguinte forma:

<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>

Atribuir a classe de estilo ao ShellItem aplicará essas cores a todas as guias nessa seção.

Agora vamos passar para as guias superiores. Para ter conteúdo navegável nas guias superiores, adicione vários itens ShellContent em um único ShellSection. O estilo será aplicado exatamente como no exemplo anterior para as guias inferiores. Eis o código:

<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>

O roteiro

Há muito mais para descobrir no Shell do Xamarin.Forms. Eu poderia continuar descrevendo como personalizar a barra de navegação, o botão de reversão e tudo sobre o manipulador de pesquisa super avançado que facilita ainda mais a adição de uma pesquisa a uma página. Esses recursos e muitos mais já estão disponíveis e serão documentados à medida que nos aproximarmos da versão estável.

A jornada do Shell está apenas começando. Ouvimos claramente dos desenvolvedores do Xamarin.Forms que frequentemente é preciso fazer com que seus aplicativos iOS e Android pareçam iguais ou quase iguais. Para resolver isso, planejamos lançar o Material Shell, que é uma implementação do Shell que aplica o estilo do Material Design do Google como ponto de partida para todos os controles compatíveis. Os controles ainda são nativos, portanto, não há comprometimentos de recurso ou desempenho.

As transições de navegação e segues também já ficarão disponíveis. Com as transições, você pode controlar como a animação de uma página passa para outra (da esquerda para a direita, da direita para a esquerda, crossfade, ondulação e muito mais). Os segues são uma maneira declarativa de dizer: "Quando essa ação de botão acontecer, execute essa rota.” Isso reduz a necessidade de gravar o código de navegação GoToAsync e expressa com mais clareza como as coisas estão conectadas no XAML. Ao combinar transições e o Material Shell, poderemos fornecer algumas animações adicionais, como a animação Hero, em que um elemento, como um ícone de imagem, transita de uma página para outra.

Comece a explorar hoje mesmo

O Shell do Xamarin.Forms está disponível hoje na versão prévia do Xamarin.Forms 4.0 e inclui incríveis novos recursos como CollectionView, CarouselView e o novo Material Visual que facilita ainda mais a iniciação de seus aplicativos do Xamarin.Forms a partir de um ponto de estilo comum e consistente da interface do usuário, em vez de um ponto em branco específico da plataforma. Use o gerenciador de pacotes NuGet do Visual Studio para atualizar para a versão 4.0-pre1, alternando a opção de pré-lançamento.

Para facilitar ainda mais, criamos um pacote atualizado de modelos de projeto que são unificados no Shell e fornecem a versão 4.0-pre por padrão. Faça o download e instale os modelos a partir aka.ms/xf-shell-templates. Depois de fazer isso, novos modelos baseados no Shell estarão disponíveis quando você criar um novo projeto do Xamarin.Forms.

À medida que o pré-lançamento do Visual Studio 2019 continua a evoluir, o Xamarin.Forms 4.0 e o Shell também continuarão sua evolução. Precisamos de seus comentários. Deixe-nos sua opinião e experiências, visitando aka.ms/xf-4-feedback.


David Ortinau é gerente sênior de programas para Ferramentas do Desenvolvedor Móvel da Microsoft e tem como foco o Xamarin.Forms. Desenvolvedor do .NET desde 2002 e versado em diversas linguagens de programação, Ortinau desenvolveu experiências na Web, ambientais e móveis para uma ampla variedade de setores. Após vários sucessos com startups de tecnologia e com sua própria empresa de software, Ortinau se juntou à Microsoft para seguir sua paixão: criar ferramentas que ajudassem os desenvolvedores a criar melhores experiências de aplicativos. Quando não está com sua família ou trabalhando em um computador, ele cavalga pela floresta.

Agradecemos aos seguintes especialistas técnicos da Microsoft pela revisão deste artigo: David Britch, Jason Smith


Discuta esse artigo no fórum do MSDN Magazine