Salvando as receitas da vovó com Xamarin.Forms
Publicados: 2022-03-10Minha avó faz os melhores, mais fofos, pães fracos nos joelhos que alguém já provou. O problema é que há uma tonelada de ingredientes secretos (e não estou falando apenas de amor) que entram nesses pães, e esses ingredientes e instruções estão todos armazenados na cabeça da minha avó.
Todos nós temos receitas de família assim e, em vez de possivelmente esquecê-las, neste artigo vamos criar um aplicativo móvel para iOS e Android usando Xamarin.Forms que as salvará para mim e para as futuras gerações da minha família!

Portanto, se você está interessado em escrever aplicativos móveis, mas não tem tempo para escrever o mesmo aplicativo repetidamente para cada plataforma, este artigo é para você! Não se preocupe se você não sabe C# de uma Salada de Pretzel de Morango; Escrevo aplicativos Xamarin há mais de 8 anos, e este artigo é um tour pelo Xamarin.Forms que pretende fornecer informações suficientes para você começar a aprender por conta própria.
O que é esse material Xamarin?
Mais do que apenas uma palavra divertida para dizer, o Xamarin permite que os desenvolvedores criem aplicativos iOS e Android nativos usando exatamente os mesmos SDKs e controles de interface do usuário disponíveis no Swift e XCode para iOS ou Java e Android Studio para Android.

A diferença é que os aplicativos são desenvolvidos com C# usando o .NET Framework e Visual Studio ou Visual Studio para Mac. Os aplicativos que resultam, no entanto, são exatamente os mesmos. Eles se parecem, se comportam e se comportam exatamente como aplicativos nativos escritos em Objective-C, Swift ou Java.
O Xamarin brilha quando se trata de compartilhamento de código. Um desenvolvedor pode criar e personalizar sua interface do usuário para cada plataforma usando controles nativos e SDKs, mas depois escrever uma biblioteca de lógica de aplicativo compartilhada que é compartilhada entre plataformas.

É nesse compartilhamento de código que uma tremenda economia de tempo pode ser obtida.
E como os deliciosos pães que minha avó faz, uma vez que teve o gosto de compartilhar código - é difícil não desejar mais - e é aí que entra o Xamarin.Forms.
Xamarin.Forms
O Xamarin.Forms pega o conceito de desenvolvimento tradicional do Xamarin e adiciona uma camada de abstração a ele.
Em vez de desenvolver a interface do usuário para iOS e Android separadamente, o Xamarin.Forms apresenta um kit de ferramentas de interface do usuário que permite escrever aplicativos móveis nativos a partir de uma única base de código.
Pense desta forma: você tem um aplicativo que precisa de um botão. Cada plataforma tem o conceito de um botão. Por que você deveria escrever a interface do usuário várias vezes quando sabe que tudo o que o usuário do seu aplicativo precisa fazer é tocar em um botão?
Esse é um dos problemas que o Xamarin.Forms resolve.
Ele fornece um kit de ferramentas dos controles e eventos de interação do usuário mais usados para eles, portanto, só precisamos escrever as interfaces do usuário para nossos aplicativos uma vez. Vale a pena notar que você também não está limitado aos controles que o Xamarin.Forms fornece — você ainda pode usar controles encontrados em apenas uma única plataforma dentro de um aplicativo Xamarin.Forms. Além disso, podemos compartilhar a lógica do aplicativo entre plataformas como antes.
As estatísticas de compartilhamento de código para aplicativos desenvolvidos com Xamarin.Forms podem estar fora dos gráficos. Um aplicativo de organização de conferências tem 93% de seu código compartilhado no iOS e 91% no Android. O aplicativo é de código aberto. Dê uma olhada no código.
Xamarin.Forms fornece mais do que controles de interface do usuário. Ele também contém uma estrutura MVVM, um serviço de mensagens pub/sub, uma API de animação e um serviço de dependência, além de outros.
Mas hoje, vamos nos concentrar nos recursos de interface do usuário para criar nosso aplicativo gerenciador de receitas.
O aplicativo que vamos construir
O aplicativo gerenciador de receitas terá uma interface de usuário direta. Estaremos trabalhando na cozinha, por isso precisa ser fácil de usar!
Será composto por 3 telas . O primeiro mostrará uma lista de todas as receitas atualmente carregadas no aplicativo.

Então, tocando em uma dessas receitas, você poderá ver seus detalhes em uma segunda tela:

A partir daí, você pode tocar em um botão de edição para fazer alterações na receita na terceira tela:

Você também pode acessar essa tela tocando no botão adicionar na tela da lista de receitas.
O Ambiente de Desenvolvimento
Os aplicativos Xamarin são criados com C# e .NET, usando o Visual Studio no Windows ou o Visual Studio para Mac no Mac, mas você também precisa ter os SDKs e ferramentas do iOS ou Android instalados. Instalar tudo na ordem correta pode ser um problema, no entanto, os instaladores do Visual Studio cuidarão de apenas instalar o IDE, mas também as ferramentas da plataforma.
Embora um Mac seja sempre necessário para criar aplicativos iOS, com o Xamarin você ainda pode desenvolver e depurar esses aplicativos do Visual Studio no Windows! Portanto, se o Windows é o seu congestionamento, não há necessidade de alterar completamente seus ambientes.
Agora vamos ver como o Xamarin.Forms pode nos ajudar a salvar algumas receitas de família a partir de uma base de código!
Página da lista de receitas: Layout da interface do usuário
Vamos começar falando sobre como vamos fazer o layout da interface do nosso aplicativo de economia de receitas!
No geral, cada tela no Xamarin.Forms é composta por 3 elementos. Uma Page
. Pelo menos um elemento chamado Layout
. E pelo menos um Control
.
A página
A página é a coisa que hospeda tudo exibido na tela ao mesmo tempo. A Page
também é central na navegação dentro de um aplicativo.

Informamos ao Xamarin.Forms qual Page
exibir por meio de um serviço de navegação . Esse serviço, então, cuidará de exibir qualquer página de maneira apropriada e nativa para o sistema operacional.
Em outras palavras, o código para navegar entre as telas também foi abstraído!
Finalmente, embora não seja a única maneira de fazer isso, codifico a interface do usuário de minhas Page
em XAML. (A outra maneira seria usar C#.) XAML é uma linguagem de marcação que descreve a aparência de uma página. E por enquanto, basta dizer, é meio parecido com HTML.
O layout
Todos os controles em uma página são organizados por algo chamado Layout.

Um ou mais layouts podem ser adicionados a uma página.

Existem vários tipos diferentes de Layouts no Forms. Alguns dos mais comuns incluem os layouts Stack, Absolute, Relative, Grid, Scroll e Flex.

Os controles
Então, finalmente, há os controles. Esses são os widgets do seu aplicativo com os quais o usuário interage.

Os formulários vêm com muitos controles que serão usados independentemente do tipo de aplicativo que você estiver criando. Coisas como rótulos, botões, caixas de entrada, imagens e, claro, visualizações de lista.
Ao adicionar um controle a uma tela, você o adiciona a um layout. É o layout que se encarrega de descobrir onde exatamente na tela o controle deve aparecer.

Então para gerar as seguintes telas no iOS e Android respectivamente:

Eu usei este XAML:
<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="https://xamarin.com/schemas/2014/forms" xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml" x:Class="SmashingRecipe.RecipeListPage" Title="Recipes"> <ContentPage.Content> <StackLayout> <ListView x:Name="recipesList"> <ListView.ItemTemplate> <DataTemplate> <TextCell Text="{Binding Name}"/> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage.Content> <ContentPage.ToolbarItems> <ToolbarItem Text="Add" /> </ContentPage.ToolbarItems> </ContentPage>
Há algumas coisas importantes acontecendo aqui.
O primeiro é o <StackLayout>
. Isso está dizendo ao Forms para organizar todos os controles que seguem em uma pilha.
Acontece que há apenas um único controle no layout, e esse é um <ListView>
, e vamos dar um nome a ele para que possamos fazer referência a ele mais tarde.
Depois, há um pouco de cerimônia clichê no ListView
antes de chegarmos ao que estamos procurando: o <TextCell>
. Isso está dizendo ao Forms para exibir texto simples em cada célula da lista.
Informamos ao <TextCell>
o texto que queremos que ele exiba por meio de uma técnica chamada Data Binding . A sintaxe se parece com Text="{Binding Name}"
. Onde Name
é uma propriedade de uma classe Recipe
que modela… bem, Receitas.
Então, como as receitas são adicionadas à lista?
Junto com cada arquivo XAML, há um arquivo “code-behind”. Esse code-behind nos permite fazer coisas como lidar com eventos de interação do usuário, configurar ou fazer outra lógica de aplicativo.

Há uma função que pode ser substituída em cada Page
chamada OnAppearing
- que como tenho certeza que você adivinhou - é chamada quando a Page
aparece.
protected override void OnAppearing() { base.OnAppearing(); recipesList.ItemsSource = null; recipesList.ItemsSource = App.AllRecipes; }
Observe as recipesList.ItemsSource = AllRecipes;
Isso está dizendo ao ListView
– “Ei! Todos os seus dados são encontrados no App.AllRecipes
enumerável (uma variável de todo o aplicativo) e você pode usar qualquer uma das propriedades de seu objeto filho para fazer o bind!”.
Uma lista de receitas está tudo bem - mas você não pode assar nada sem primeiro ver os detalhes da receita - e vamos cuidar disso a seguir.
Manipulação de eventos
Sem responder aos toques do usuário, nosso aplicativo nada mais é do que uma lista de deliciosas receitas sonoras. Parecem bons, mas sem saber cozinhá-los, não adianta muito!
Vamos fazer com que cada célula do ListView
responda aos toques para que possamos ver como fazer a receita!
No arquivo code-behind RecipeListPage
, podemos adicionar manipuladores de eventos aos controles para ouvir e reagir aos eventos de interação do usuário.
Manipulando eventos de toque na exibição de lista, então:
recipesList.ItemSelected += async (sender, eventArgs) => { if (eventArgs.SelectedItem != null) { var detailPage = new RecipeDetailPage(eventArgs.SelectedItem as Recipe); await Navigation.PushAsync(detailPage); recipesList.SelectedItem = null; } };
Tem coisas legais acontecendo lá.
Sempre que alguém seleciona uma linha, ItemSelected
é acionado no ListView
.
Dos argumentos que são passados para o manipulador, o objeto eventArgs
tem uma propriedade SelectedItem
que é o que está vinculado ao ListView
de antes.
No nosso caso, essa é a classe Recipe
. (Portanto, não precisamos procurar o objeto na fonte mestre - ele é passado para nós.)
Página de detalhes da receita
Claro, há uma página que nos mostra os ingredientes secretos e as instruções de como fazer cada receita, mas como essa página é exibida?

Observe o await Navigation.PushAsync(detailPage);
linha de cima. O objeto Navigation
é um objeto independente de plataforma que trata as transições de página de forma nativa para cada plataforma.
Agora vamos dar uma olhada na página de detalhes da receita:

Esta página também é criada com XAML. Porém, o Layout
utilizado (FlexLayout) é bem legal, pois é inspirado no CSS Flexbox.
<ContentPage.Content> <ScrollView> <FlexLayout AlignItems="Start" AlignContent="Start" Wrap="Wrap"> <Image Source="buns.png" FlexLayout.Basis="100%" /> <Label Text="{Binding Name}" HorizontalTextAlignment="Center" TextColor="#01487E" FontAttributes="Bold" FontSize="Large" Margin="10, 10" /> <BoxView FlexLayout.Basis="100%" HeightRequest="0" /> <Label Text="Ingredients" FontAttributes="Bold" FontSize="Medium" TextColor="#EE3F60" Margin="10,10" HorizontalOptions="FillAndExpand" /> <BoxView FlexLayout.Basis="100%" HeightRequest="0" /> <Label Text="{Binding Ingredients}" Margin="10,10" FontSize="Small" /> <BoxView FlexLayout.Basis="100%" HeightRequest="0" /> <Label Text="Directions" FontAttributes="Bold" FontSize="Medium" TextColor="#EE3F60" Margin="10,10" HorizontalOptions="FillAndExpand" /> <BoxView FlexLayout.Basis="100%" HeightRequest="0" /> <Label Text="{Binding Directions}" Margin="10,10" FontSize="Small" /> </FlexLayout> </ScrollView> </ContentPage.Content>
O FlexLayout
organizará seus controles em linhas ou colunas. O grande benefício vem com o fato de que ele pode detectar automaticamente quanto espaço resta na tela para colocar um controle e, se não houver o suficiente, ele pode criar automaticamente uma nova linha ou coluna para acomodá-lo!
Isso ajuda muito ao lidar com vários tamanhos de tela, que existem em abundância no desenvolvimento móvel.
Bem, com o FlexLayout
nos ajudando a manter a tela de detalhes com boa aparência, ainda precisamos editar essas receitas, certo?
Você provavelmente notou isso:
<ToolbarItem Text="Edit" Clicked="Edit_Clicked" />
Essa linha é responsável por colocar um botão na barra de ferramentas do aplicativo. O Clicked="Edit_Clicked"
informa ao botão que, quando for clicado, procure no código por trás uma função com esse nome e, em seguida, execute seu código.
O que, neste caso, seria instanciar a página de edição de receita e enviá-la para nossa pilha de navegação usando o objeto Navigation
mencionado anteriormente.
Página de edição de receita
Uma página com uma lista de receitas: confira! Uma página com todos os detalhes para fazer as receitas: confira! Tudo o que resta agora é criar a página que usamos para inserir ou alterar uma receita enquanto observamos a vovó fazer sua mágica!
Primeiro, confira as telas:

E agora o código:
<ContentPage.Content> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <TableView Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Intent="Form" HasUnevenRows="true"> <TableSection Title="General"> <EntryCell x:Name="recipeNameCell" Label="Name" /> </TableSection> <TableSection Title="Ingredients"> <ViewCell> <StackLayout Padding="15"> <Editor x:Name="ingredientsCell" /> </StackLayout> </ViewCell> </TableSection> <TableSection Title="Directions"> <ViewCell> <StackLayout Padding="15"> <Editor x:Name="directionsCell" /> </StackLayout> </ViewCell> </TableSection> </TableView> <Button Text="Save" Grid.Row="1" Grid.Column="0" BackgroundColor="#EE3F60" TextColor="White" x:Name="saveButton" /> <Button Text="Cancel" Grid.Row="1" Grid.Column="1" BackgroundColor="#4CC7F2" TextColor="White" x:Name="cancelButton" /> </Grid> </ContentPage.Content>
Há um pouco mais de código aqui, e isso é porque estou usando o layout Grid
para especificar como tudo deve ser disposto em um padrão bidimensional.
E também não observe nenhuma vinculação de dados aqui. Porque eu queria dar um exemplo de como alguém preencheria os controles puramente a partir do código por trás do arquivo:
void InitializePage() { Title = TheRecipe.Name ?? "New Recipe"; recipeNameCell.Text = TheRecipe.Name; ingredientsCell.Text = TheRecipe.Ingredients; directionsCell.Text = TheRecipe.Directions; saveButton.Clicked += async (sender, args) => { SaveRecipe(); await CloseWindow(); }; cancelButton.Clicked += async (sender, args) => { await CloseWindow(); }; }
Vê aquela propriedade TheRecipe
? É no nível da página, contém todos os dados de uma receita específica e é definido no construtor da página.
Em segundo lugar, os manipuladores de eventos Clicked
para saveButton
e cancelButton
são totalmente .NET-ified (e sim, eu invento minhas próprias palavras com bastante frequência).
Eu digo que eles são .NET-ified porque a sintaxe para lidar com esse evento não é nativa de Java nem Objective-C. Quando o aplicativo for executado no Android ou iOS, o comportamento será exatamente como um Android Click ou um iOS TouchUpInside.
E, como você pode ver, cada um desses manipuladores de eventos de clique está invocando funções apropriadas que salvam a receita e dispensam a página ou apenas dispensam a página.
Aí está - nós temos a interface do usuário para salvar as receitas de agora até o fim dos tempos!
CSS O que?!? Ou tornando o aplicativo bonito
Deixando o melhor para o final: o Xamarin.Forms 3.0 nos dá — entre outras coisas — a capacidade de estilizar controles usando CSS!
O CSS do Xamarin.Forms não é 100% o que você pode estar acostumado no desenvolvimento web. Mas é perto o suficiente para que qualquer pessoa familiarizada com CSS se sinta em casa. Assim como eu na casa da vovó!
Então, vamos pegar a página Detalhes da Receita e refatorá-la, para que ela use Folhas de Estilo em Cascata para definir os elementos visuais em vez de definir tudo diretamente embutido no XAML.
O primeiro passo é criar o documento CSS! Neste caso ficará assim:
.flexContent { align-items: flex-start; align-content: flex-start; flex-wrap: wrap; } image { flex-basis: 100%; } .spacer { flex-basis: 100%; height: 0; } .foodHeader { font-size: large; font-weight: bold; color: #01487E; margin: 10 10; } .dataLabel { font-size: medium; font-weight: bold; color: #EE3F60; margin: 10 10; } .data { font-size: small; margin: 10 10; }
Na maioria das vezes, parece CSS. Tem aulas lá. Há um único seletor para um tipo de classe, Image
. E, em seguida, um bando de setters de propriedade.
Alguns desses setters de propriedade, como flex-wrap
ou flex-basis
são específicos do Xamarin.Forms. Daqui para frente, a equipe irá prefixar aqueles com xf-
para seguir as práticas padrão.
O próximo passo será aplicá-lo aos controles XAML.
<ContentPage.Resources> <StyleSheet Source="../Styles/RecipeDetailStyle.css" /> </ContentPage.Resources> <ContentPage.Content> <ScrollView> <FlexLayout StyleClass="flexContent"> <Image Source="buns.png" /> <Label Text="{Binding Name}" StyleClass="foodHeader" /> <BoxView StyleClass="spacer" /> <Label Text="Ingredients" StyleClass="dataLabel" HorizontalOptions="FillAndExpand" /> <BoxView StyleClass="spacer" /> <Label Text="{Binding Ingredients}" StyleClass="data" /> <BoxView StyleClass="spacer" /> <Label Text="Directions" StyleClass="dataLabel" HorizontalOptions="FillAndExpand" /> <BoxView StyleClass="spacer" /> <Label Text="{Binding Directions}" StyleClass="data" /> </FlexLayout> </ScrollView> </ContentPage.Content>
Aqui está o que parecia antes.
No Xamarin.Forms, para fazer referência ao documento CSS, adicione um <StyleSheet Source="YOUR DOC PATH" />
. Em seguida, você pode fazer referência às classes em cada controle por meio da propriedade StyleClass
.
Ele definitivamente limpa o XAML e torna a intenção do controle mais clara também. Por exemplo, agora é bem óbvio o que esses <BoxView StyleClass="spacer" />
estão fazendo!
E a Image
fica estilizada tudo porque é uma Image
e da maneira que definimos o seletor no CSS.
Para ter certeza, o CSS no Xamarin.Forms não é totalmente implementado como seu primo da web, mas ainda é muito legal. Você tem seletores, classes, pode definir propriedades e, claro, toda essa coisa de cascata acontecendo!
Resumo
Três telas, duas plataformas, um artigo e receitas infinitas salvas! E sabe o que mais? Você pode criar aplicativos com Xamarin.Forms para mais do que Android e iOS. Você pode criar plataformas UWP, macOS e até Samsung Tizen!

Xamarin.Forms é um kit de ferramentas de interface do usuário que permite criar aplicativos escrevendo a interface do usuário uma vez e tendo a interface do usuário renderizada nativamente nas principais plataformas.
Ele faz isso fornecendo um SDK que é uma abstração dos controles mais usados nas plataformas. Além da qualidade da interface do usuário, o Xamarin.Forms também fornece uma estrutura MVVM completa, um serviço de mensagens pub/sub, uma API de animação e um serviço de dependência.
O Xamarin.Forms também oferece os mesmos benefícios de código que o desenvolvimento tradicional do Xamarin oferece. Qualquer lógica de aplicativo é compartilhada em todas as plataformas. E você pode desenvolver todos os seus aplicativos com um único IDE usando uma única linguagem - isso é muito legal!
Onde a próxima? Baixe o código-fonte para este aplicativo Xamarin.Forms para experimentar você mesmo. Então, para saber mais sobre o Xamarin.Forms, incluindo a capacidade de criar um aplicativo em seu navegador, confira este tutorial online!