You are on page 1of 200

#Dominando o Xamarin.

Forms

1
#Dominando o Xamarin.Forms

Diga não à pirataria

O leitor que adquiriu o e-book legalmente no site AlbertEije.COM poderá


imprimir o conteúdo para seu uso pessoal.

A cópia do conteúdo do livro sem autorização configura crime. Além de


contribuir para a criminalidade, a cópia ilegal desestimula o autor de realizar
novos trabalhos. Todos saem perdendo com a pirataria.

2
#Dominando o Xamarin.Forms

Autor
Apresentação
Albert Eije é bacharel em Sistemas de Como funcionário do Banco do Brasil,
Informação e especialista em Engenharia de trabalhou nas Diretorias de Governo e
Software. Possui larga experiência no Tecnologia.
desenvolvimento dos mais diversos tipos de
sistemas. Teve contato com sistemas de grande porte e
participou do desenvolvimento de vários
O autor iniciou sua investida no universo da módulos do sistema do Banco do Brasil, o
informática nos idos de 1990. Na época seu maior banco da América Latina.
interesse era por computação gráfica:
CorelDRAW, PageMaker, Photoshop, etc. Atualmente faz parte da Equipe T2Ti, que já
formou milhares de profissionais para o
Com o tempo conheceu o mundo da mercado de desenvolvimento de software,
programação, primeiro através do Clipper, criando treinamentos personalizados e
seguido do Delphi e várias outras linguagens e exclusivos não encontrados em outras
ferramentas. Desenvolver sistemas passou a empresas de treinamento.
ser o seu negócio. No início focou em
pequenas e médias empresas: condomínios, Escreveu dois livros que foram publicados pela
livrarias, construtoras, etc. Editora Ciência Moderna e outros 20 e-books
que estão disponíveis no seu site:
Um desenvolvedor que trabalha por conta AlbertEije.COM.
própria costuma ser o faz-tudo da empresa
por um bom tempo: analista, programador, Contate o autor através do site
vendedor, suporte, etc. AlbertEije.COM.

3
#Dominando o Xamarin.Forms

Xamarin.Forms
Introdução
O Xamarin.Forms é uma plataforma fantástica Em relação ao suporte para o Windows, o
para desenvolvimento mobile. É possível Xamarin.Forms inclui o (WinRT) para
desenvolver para iOS, Android e Windows. Ele dispositivos Windows 8.1 e Windows Phone
permite escrever código compartilhado em C# 8.1.
e XAML (Extensible Application Markup
Language). O Xamarin.Forms se encarrega de Inclui ainda a UWP (Universal Windows
mapear tudo para controles nativos de cada Platform), que é uma espécie de Windows
plataforma. Runtime para Windows 10 e Windows 10
Mobile numa mesma aplicação.

4
#Dominando o Xamarin.Forms

Xamarin.Forms
Requisitos
Vimos que é possível criar apps para várias Os testes em dispositivos Android e Windows
plataformas com o Xamarin.Forms. As podem ser realizados tranquilamente na sua
plataformas que você decidir usar para máquina Windows onde o Visual Studio está
desenvolvimento vão definir seus requisitos de instalado.
hardware e software.

Para desenvolver aplicações para o iOS, você


vai precisar de um computador Apple com
uma versão do Mac, a aplicação Xcode da
Apple e da plataforma Xamarin, que inclui o
Xamarin Studio. É possível apontar do Visual
Studio para sua máquina Mac, realizando
testes pela rede.

5
#Dominando o Xamarin.Forms

Xamarin.Forms
Uma Aplicação – Várias Plataformas
Imagine criar aquela aplicação “perfeita” para E quais são os desafios que o Xamarin.Forms
iOS. Um estouro! Múltiplas vendas. O próximo enfrenta para conseguir fazer a sua mágica?
passo será criar a aplicação para as outras
plataformas, pelo menos para o Android. Mas
vai escrever tudo de novo em outra
linguagem?

Esse o problema que tira o sono de muitos


empreendedores e desenvolvedores. Não é
nada divertido fazer a mesma aplicação com
outra tecnologia. E a manutenção? Para cada
correção ou nova funcionalidade você terá dois
trabalhos!

A saída então é procurar uma maneira de


desenvolver a aplicação de tal forma que ela
funcione em várias plataformas.

Essa a mágica do Xamarin.Forms.

6
#Dominando o Xamarin.Forms

Xamarin.Forms
Desafio 01 – Diferentes Paradigmas de Interface com o Usuário
As três plataformas (iOS, Android e Windows)
se comportam de forma similar, permitindo
que o usuário interaja com as aplicações com
o toque na tela, mas elas são muito diferentes
nos detalhes.

Cada uma tem maneiras distintas de navegar


pela aplicação e através das páginas, diferente
convenções para apresentação de dados,
maneiras distintas de invocar e exibir menus,
etc.

Os usuários de uma plataforma já estão


acostumados com as convenções dela. Alguns
não trocam de plataforma por conta disso.
Certamente isso influencia o desenvolvedor de
aplicações, que não vai criar uma app com
“cara e comportamento” de Android para o
iOS, pois os usuários vão detestar.

7
#Dominando o Xamarin.Forms

Xamarin.Forms
Desafio 02 – Diferentes Ambientes de Desenvolvimento
Os desenvolvedores estão acostumados a
trabalhar com ambientes integrados de
desenvolvimento, as conhecidas IDEs.

Pois saiba que para cada plataforma existe


uma IDE diferente:


Para o desenvolvimento de aplicações iOS:
Xcode em um Mac.

Para o desenvolvimento de aplicações
Android: Android Studio em vários SOs.

Para o desenvolvimento de aplicações
Windows: Visual Studio em um PC.

Criar uma App para uma só plataforma é uma


opção? Aprender três IDEs é a saída?
Sabemos que não, por isso o esforço de criar
uma ferramenta que resolva esse problema.

8
#Dominando o Xamarin.Forms

Xamarin.Forms
Desafio 03 – Diferentes Interfaces de Programação
As três plataformas são baseadas em
diferentes sistemas operacionais com
diferentes APIs. Em muitos casos, as
plataformas implementam tipos similares, mas
com nomes diferentes. Por exemplo:

As três plataformas tem um componente que


permite que o usuário selecione um valor
booleano:


No iOS, esse componente é uma “view”
chamada UISwitch.

No Android é um “widget” chamado Switch.

No Windows é um “control” chamado
ToggleSwitch.

Evidentemente as diferenças vão além dos


nomes, incluindo aí as propriedades e eventos.

9
#Dominando o Xamarin.Forms

Xamarin.Forms
Desafio 04 – Diferentes Linguagens de Programação
Cada plataforma está associada às seguintes
linguagens de programação:


No iOS: Objective C.

No Android: Java.

No Windows: C#.

Podemos dizer que essas linguagens são


primas, pois são orientadas a objetos e
derivam do C. Mas são primas distantes!

Evidentemente esses desafios não são


enfrentados apenas pelo Xamarin. O mercado
de desenvolvimento de software está sempre
buscando soluções para resolver os desafios
propostos. Além do Xamarin, temos outras?

10
#Dominando o Xamarin.Forms

Apps Híbridas
Intel XDK
O XDK é a ferramenta que possibilita o O webview tem menos recursos que um
desenvolvimento das Apps híbridas. Mas não browser. A vantagem é a capacidade de ser
apenas isso, ele permite que você desenvolva estendido através dos plugins de código nativo
de forma visual, realize testes utilizando uma do Cordova (PhoneGap).
ferramenta instalada no dispositivo, debugue a
aplicação diretamente no dispositivo, crie seu O XDK é gratuito.
pacote para publicação nas lojas e muito mais.
Se você já for um desenvolvedor web facilita
Além das aplicações híbridas, é possível criar muito. Senão, terá que aprender as linguagens
Apps HTML5 nativas e até mesmo importar HTML, JavaScript e CSS, pelo menos. Além
projetos HTML5 desenvolvidos anteriormente. dos plugins que serão utilizados para acessar
os recursos dos dispositivos. As Apps
É possível instalar o XDK no Windows, Linux e construídas não são nativas, pois rodam no
OSX. webview.

O XDK cumpre a promessa: “escreva uma vez,


rode em qualquer lugar”, em inglês “write-
once, run-anywhere”.

As Apps construídas no XDK rodam num


webview (navegador embutido) e estão
limitadas aos recursos do webview mais a
combinação dos plugins utilizados.

11
#Dominando o Xamarin.Forms

Delphi
Firemonkey
O Delphi tem realizado vários lançamentos por Com o FMX você não precisa manter projetos
conta das novidades relacionadas ao mundo de desenvolvimento separados para criar sua
mobile. A base para o desenvolvimento de aplicação de modo nativo para distintos
apps no Delphi chama-se FireMonkey. dispositivos (PCs, tablets e smartphones) em
múltiplas plataformas (Windows, Mac, iOS e
O FireMonkey não foi desenvolvido pela Android). O FMX facilita a criação de aplicações
Embarcadero. Foi projetado pelo russo Eugene verdadeiramente nativas e livres de scripts
Kryukov para ser a nova geração do que tiram máximo proveito das capacidades e
framework VGScene. Em 2011 a Embarcadero da performance dos dispositivos subjacentes.
comprou o projeto, que é parte integrante do
Delphi, C++ Builder e RAD Studio desde a Um visual eletrizante conta pouco se a
versão XE2. experiência do usuário for a mesma que andar
de carroça. As aplicações da plataforma FMX
Observe a seguir a descrição do framework contam com todo o poder de hardware
copiada do site da Embarcadero: atualmente disponível, com desempenho
nativo de CPU e visuais capacitados por GPU
O FireMonkey (FMX) framework é a plataforma para PC, tablets e dispositivos móveis.
de desenvolvimento de aplicações e tempo de
execução por trás do RAD Studio, do Delphi e O Firemonkey é pago. A aplicação é nativa.
do C++Builder. FMX foi desenhada para Você programa numa só linguagem e usando a
equipes que estejam construindo aplicações IDE do Delphi.
multidispositivos verdadeiramente nativas
para Windows, Mac, Android e iOS.

12
#Dominando o Xamarin.Forms

C#
Xamarin
No C# podemos construir aplicações nativas O objetivo da plataforma Xamarim é usar a
para o Windows Phone. Para construir mesma linguagem, API e estrutura de dados
aplicações multiplataforma, temos o Mono. O para compartilhar o código da aplicação em
Mono é uma implementação Open Source do todas as plataformas: Windows, Mac, Android
framework .NET, baseado nos padrões ECMA. e iOS.
O Mono é patrocinado pela Xamarim.
Para desenhar a aplicação é preciso utilizar
Há um tempo o Xamarin era comercializado estratégias diferentes. Dessa maneira, o
separado do Visual Studio. Existe até mesmo o desenvolvedor precisa desenhar a tela da App
Xamarin Studio. Agora o Xamarin já vem com iOS num lugar, da App Android em outro e da
o Visual Studio e é gratuito! App Windows em outro, embora o código seja
compartilhado.

13
#Dominando o Xamarin.Forms

C#
Xamarin
Estima-se que 75% do código seria E é aí que entra o Xamarin.Forms. Com ele é
compartilhado usando essa estratégia. Mas, possível desenhar a aplicação uma única vez e
ainda assim, o desenvolvedor teria o trabalho compartilhar quase 100% do código! E como
de desenhar as telas separadamente. saber qual usar?

14
#Dominando o Xamarin.Forms

C#
Xamarin
A vantagem de ter várias plataformas como A parte da aplicação que é independente da
alvo e apenas uma linguagem de programação plataforma pode ser isolada e, no contexto do
é que é possível compartilhar código entre as Xamarin, colocado em um projeto separado.
Apps que serão criadas. Tal projeto pode funcionar de duas maneiras:

Antes do código ser compartilhado, a aplicação ●


Shared Asset Project (SAP): consiste
precisa ser estruturada para este propósito. simplesmente em código e outros arquivos
importantes (assets ou recursos) que
Para que isso seja feito da melhor forma podem ser acessados a partir de outros
possível, deve-se utilizar o padrão MVVM projetos.
(Model-View-ViewModel), que é uma evolução ●
Portable Class Library (PCL): fecha todo o
do MVC (Model-View-Control). código comum numa DLL que pode ser
referenciada em outros projetos.
O MVVM separa o código em camadas:


Model (os dados básicos). Independente do método que você escolher,

View (a interface do usuário, incluindo os tal código comum poderá acessar os recursos
recursos visuais e de entrada). do framework .NET, acessando todos os

ViewModel (gerencia os dados que passam recursos dele. Mas existem diferenças entre os
entre o Model e a View). métodos acima. Vejamos.

15
#Dominando o Xamarin.Forms

C#
Xamarin – SAP
A maneira mais simples de trabalhar é com o Vantagens:
SAP, conhecido como Shared Project (projeto
compartilhado). ●
Permite compartilhar código entre múltiplos
projetos.
Na imagem a seguir é possível observar dois ●
O código compartilhado pode ser ramificado
projetos (iOS e Android) e um terceiro que (branched) com base na plataforma usando
contém o código C# comum: o Shared. diretivas de compilador (por exemplo,
usando #if __ANDROID__).

É possível incluir referências específicas da
plataforma para utilização pelo código
compartilhado.

Desvantagens:


Não existe uma montagem de saída
('output' assembly). Ou seja, os arquivos
farão parte daquele projeto que aponta para
o compartilhado e serão incluídos na DLL
dele.

As refatorações que afetam o código dentro
de diretivas de compilador "inativas" não
Qualquer edição que ocorra no Projeto Shared atualizarão o código.
será compartilhada com os demais projetos.

16
#Dominando o Xamarin.Forms

C#
Xamarin – SAP
A imagem abaixo mostra a arquitetura conceitual, onde cada projeto inclui todos os arquivos do
Projeto Compartilhado (Shared Project).

17
#Dominando o Xamarin.Forms

C#
Xamarin – PCL
A PCL permite escrever código e produzir Vantagens:
bibliotecas que podem ser compartilhadas
entre múltiplas plataformas. Veja a seguir o ●
Permite compartilhar código entre múltiplos
projeto TaskyPortableLibrary e a referência projetos.
dele no projeto TaskiOS ●
As refatorações sempre atualizam todas as
referências afetadas.

Desvantagens:


Não dá pra usar diretivas de compilação.

Apenas um subconjunto do .NET está
disponível para uso.

18
#Dominando o Xamarin.Forms

C#
Xamarin – PCL
A imagem abaixo mostra a arquitetura conceitual, onde cada projeto faz referência à biblioteca
criada.

19
#Dominando o Xamarin.Forms

C#
Xamarin.Forms
Geralmente uma aplicação Xamarin.Forms consiste de cinco projetos separados para cada uma das
seguintes plataformas:


iOS para programas que rodam no iPhone, iPad, e iPod Touch.

Android para programas que rodam em tablets e telefones Android.

Universal Windows Platform (UWP) para aplicações que rodam no Windows 10 ou Windows 10
Mobile.

Windows Runtime API do Windows 8.1.

Windows Runtime API do Windows Phone 8.1.

Além desses cinco projetos, existe um sexto, contendo o código comum. No entanto, esses cinco
projetos costumam ser bem pequeno, apenas com algum código de inicialização. A parte pesada do
código fica na aplicação comum (PLC ou SAP), que contém ainda o código da interface com o
usuário.

20
#Dominando o Xamarin.Forms

C#
Xamarin.Forms
As bibliotecas “Xamarin .
Forms . Core” e “Xamarin .
Forms . Xaml” implementam
a API Xamarin.Forms.

Dependendo da plataforma, o
“Core” faz uso das bibliotecas
“Xamarin.Forms.Platform”.

Essas bibliotecas são, na


maioria dos casos, coleções
de classes chamadas
renderizadores que
transformam a interface do
Xamarin.Forms em objetos
para cada plataforma
específica.

21
#Dominando o Xamarin.Forms

C#
Xamarin.Forms
Por exemplo, digamos que você precise usar um botão booleano na tela. No Xamarin.Forms esse
controle é chamado de Slider e uma classe de mesmo nome é implementada no
Xamarin.Forms.Core. Nos renderizadores individuais de cada plataforma esse Slider é mapeado
como UISlider no iPhone, como SeekBar no Android, e como Slider no Windows Phone.

Na imagem a seguir podemos ver um pequeno programa feito com Xamarin.Forms rodando nas
três plataformas.

22
#Dominando o Xamarin.Forms

C#
Xamarin.Forms
O exemplo anterior não se limita a celulares. Veja ele rodando num iPad Air 2.

23
#Dominando o Xamarin.Forms

C#
Xamarin.Forms
E agora o mesmo exemplo rodando num Microsoft Surface Pro 3 com Windows 10.

24
#Dominando o Xamarin.Forms

C#
Xamarin.Forms
Finalmente temos a mesma aplicação feita para Windows 8.1 rodando numa máquina desktop com
Windows 10 e uma com Windows Phone 8.1 rodando num celular.

25
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
O Xamarin.Forms suporta o XAML (pronuncia-se “zammel” para rimar com “camel”). É com o XAML
que a tela é desenhada. Segue o código fonte da tela vista anteriormente.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PlatformVisuals.PlatformVisualsPage"
Title="Visuals">
<StackLayout Padding="10,0">
<Label Text="Hello, Xamarin.Forms!"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<Button Text = "Click Me!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<Switch VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<Slider VerticalOptions="CenterAndExpand" />
</StackLayout>
<ContentPage.ToolbarItems>

26
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
<ToolbarItem Text="edit" Order="Primary">
<ToolbarItem.Icon>
<OnPlatform x:TypeArguments="FileImageSource"
iOS="edit.png"
Android="ic_action_edit.png"
WinPhone="Images/edit.png" />
</ToolbarItem.Icon>
</ToolbarItem>
<ToolbarItem Text="search" Order="Primary">
<ToolbarItem.Icon>
<OnPlatform x:TypeArguments="FileImageSource"
iOS="search.png"
Android="ic_action_search.png"
WinPhone="Images/feature.search.png" />
</ToolbarItem.Icon>
</ToolbarItem>
<ToolbarItem Text="refresh" Order="Primary">
<ToolbarItem.Icon>
<OnPlatform x:TypeArguments="FileImageSource"
iOS="reload.png"
Android="ic_action_refresh.png"
WinPhone="Images/refresh.png" />
</ToolbarItem.Icon>
</ToolbarItem>
<ToolbarItem Text="explore" Order="Secondary" />
<ToolbarItem Text="discover" Order="Secondary" />
<ToolbarItem Text="evolve" Order="Secondary" />
</ContentPage.ToolbarItems> 27
</ContentPage>
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Observe no código anterior o elemento A ideia do Xamarin.Forms é facilitar e
“ToolbarItem”. Ele contém uma tag chamada trabalhar o mínimo possível com código
”OnPlatform”. Essa é uma das várias técnicas dependente de plataforma. Se a sua aplicação
no Xamarin.Forms para introduzir código depende na sua maior parte de código
vinculado à plataforma. No caso em questão, dependente da plataforma, é interessante
foi utilizado esse recurso porque cada analisar se é melhor escolher usar o
plataforma utiliza um formato diferente de Xamarin.iOS, o Xamarin.Android e a API
imagem, com suas devidas restrições, Windows Phone.
inclusive de tamanho.
Como saber isso? Se sua aplicação precisa de
A classe Device nos fornece facilidades uma tela rebuscada, gráficos vetoriais ou
similares, que nos permite escolher valores de interação complexa de toque na tela, o
objetos com base na plataforma. Dessa Xamarin.Forms não é a melhor opção. Agora,
maneira, é possível especificar diferentes se a aplicação é para entrada e consulta de
tamanhos de fontes, por plataforma, para citar dados, como aplicações comerciais utilizadas
um exemplo. pelas empresas (Vendas, Estoque, ERP, etc),
então o Xamarin.Forms é uma boa pedida.
Se for necessário trabalhar com algo mais
específico, como manipular o GPS, existe a
classe DependencyService, que fornece uma
maneira de fazer isso de uma forma
estruturada.

28
#Dominando o Xamarin.Forms

Xamarin.Forms
Ambiente de Desenvolvimento
Lembrando que o hardware e o software que Sendo assim, se vai desenvolver uma
você terá para trabalhar com o Xamarin.Forms aplicação para todas em todas as plataformas
vai depender das plataformas alvo. alvo, o ideal é fazer o seguinte:

Se você for trabalhar com o iOS, vai precisar ●


Ter uma máquina Mac, pode ser um Mac
de um computador Mac com o Xcode Mini, por exemplo, com o Xcode e o Xamarin
instalado. Instale ainda o Xamarin Studio no Studio instalados.
Mac. É possível desenvolver diretamente na ●
Ter uma máquina Windows (um PC) com o
máquina Mac. Mas, caso esteja trabalhando Visual Studio instalado.
com várias plataformas, você pode instalar o ●
Desenvolver tudo no PC, realizando testes
Visual Studio na sua máquina Windows e no Mac de modo remoto, quando
“achar” a máquina Mac pela rede para realizar necessário.
os testes de modo remoto. O procedimento é
simples, descomplicado. Em relação aos dispositivos, se for possível,
adquira um para cada plataforma para realizar
É possível criar as aplicações Android tanto no testes. No entanto, existem emuladores para
Xamarin Studio na máquina Mac quanto no iOS, Android e para o Windows.
Visual Studio na máquina com o Windows.
Para testar devidamente a interação do
No caso do desenvolvimento de aplicações usuário através do toque e o tempo de
para Windows, é preciso instalar o Visual resposta da aplicação, um dispositivo real é
Studio num PC com o SO Windows. essencial.

29
#Dominando o Xamarin.Forms

Xamarin.Forms
Estrutura de uma Aplicação
As interfaces de usuário modernas são
construídas com vários tipos de objetos.
Dependendo do sistema operacional, tais
objetos podem ter nomes distintos: controles,
elementos, views, widgets. Todos eles estão
dedicados aos trabalhos de visualização e
interação.

No Xamarin.Forms, os objetos que aparecem


na tela são coletivamente chamados de Visual
Elements (Elementos Visuais). Eles são
separados em três categorias: Page, Layout e
View.

A API do Xamarin define as classes da


seguinte maneira: VisualElement, Page,
Layout, e View. Tais classes e suas
descendentes são a espinha dorsal do
Xamarin.Forms. A classe VisualElement é
extremamente importante. Todo objeto
colocado na tela é um VisualElement.

30
#Dominando o Xamarin.Forms

Xamarin.Forms
Estrutura de uma Aplicação
Uma aplicação Xamarin.Forms é formada por
uma ou mais páginas. Uma página
normalmente ocupa toda a área da tela (ou a
maior parte dela).

Algumas aplicações contém apenas uma


página, enquanto outras navegam entre
múltiplas páginas. Você verá que uma das
mais comuns é a ContentPage.

Em cada página, os elementos visuais são


organizados numa hierarquia “pai-filho”. O
filho de uma ContentPage é geralmente um
Layout para organizar as Views.

Alguns Layouts tem apenas um filho, outros


possuem vários filhos, que são organizados
pelo próprio Layout. Esses filhos podem ser
outros Layouts ou Views. A organização dos
filhos vai depender do tipo de Layout.

No Xamarin.Forms, uma View é todo objeto


interativo e visual: textos, botões, etc.

31
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação
Hora de construir nossa primeira aplicação. Os exemplos deste livro serão feitos no Visual Studio
Community 2015. Selecione File/New/Project e busque a opção que aparece na imagem para criar
uma aplicação Cross-Platform. Forneça um nome para a aplicação, tal como: Hello.

32
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação
Observe que foram criados seis projetos (imagem ao lado): o
projeto PCL e outros cinco para cada plataforma: iOS
(Hello.iOS), Android (Hello.Droid), Plataforma Universal do
Windows (Hello.UWP), Windows 8.1 (Hello.Windows) e Windows
Phone (Hello.WinPhone).

Analise as configurações do projeto. Selecione Build /


Configuration Manager. Marque a caixa “Build” para todos os
projetos. Marque Deploy para todos os projetos de Apps (a
caixa não estará disponível para o projeto que não for permitido
marcar).

Configure a coluna Platform de acordo com a imagem abaixo.

33
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação
Caso não esteja vendo as barras de ferramentas do iOS e do
Android, selecione as opções: View / Toolbars / iOS e View /
Toolbars / Android.

Observe que o projeto contém seis aplicações. Uma delas terá


que ser marcada para ser inicializada.

Neste caso, o nome da aplicação ficará em negrito no Solution


Explorer. Observe na imagem ao lado que, no meu caso, o
Hello.Droid está marcado para ser iniciado.

Caso queira alterar, basta selecionar o projeto desejado com o


botão direito e selecionar a opção “Set as StartUp Project.

Observe na página seguinte como ficaria a aplicação depois de


executada nas três plataformas.

34
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação

35
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação
A aplicação criada é bem simples e nos fornece a oportunidade
de estudar o código fonte para compreender como as coisas
funcionam.

Existe uma classe chamada “App.cs” no Projeto Hello. Ela é a


responsável por desenhar o texto que você viu na tela. Abra
essa classe e observe o código.

public class App : Application


{
public App()
{
// The root page of your application
MainPage = new ContentPage
{
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Children = {
new Label {
HorizontalTextAlignment =
TextAlignment.Center,
Text = "Welcome to Xamarin Forms!"
}
}
}
}; 36
}
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação
Trata-se de uma classe pública que deriva de Application. O
construtor cria uma página principal do tipo ContentPage.

A propriedade Content pertence à ContentPage. Geralmente


essa propriedade é definida como o layout que receberá as
views, ou seja, os componentes que aparecerão na tela. No
exemplo em questão a Content foi definida para o layout
StackLayout, que arruma seus elementos filhos numa pilha.

O StackLayout tem apenas um elemento filho, que é um Label,


que é alinhado ao centro e exibe o texto que vimos
anteriormente.

No projeto PCL você ainda pode ver o arquivo packages.config


que contém os pacotes requeridos pela aplicação. Se observar
as referências, verá as bibliotecas do Xamarin.Forms lá:


Xamarin.Forms.Core

Xamarin.Forms.Xaml

Xamarin.Forms.Platform

37
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação
Nas referências dos cinco projetos, você verá o “Hello”, que é o
Projeto PCL. Observe na imagem ao lado.

Cada um dos projetos trará uma biblioteca


“Xamarin.Forms.Platform.????”. No caso do Android, visto na
imagem ao lado, temos: Xamarin.Forms.Platform.Android.

Cada uma dessas bibliotecas definem um método “Forms.Init”


que inicializa o sistema do Xamarin.Forms para cada plataforma
particular. O código de inicialização em cada plataforma precisa
chamar esse método.

Lembre que o projeto PCL deriva de App, que deriva de


Application. O código de inicialização de cada plataforma precisa
instanciar essa classe App.

Veja como se parece na classe MainActivity do Andoid (explore


as demais).

38
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação
namespace Hello.Droid
{
[Activity(Label = "Hello", Icon = "@drawable/icon", MainLauncher
= true, ConfigurationChanges = ConfigChanges.ScreenSize |
ConfigChanges.Orientation)]
public class MainActivity :
global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);

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

Observe que a classe principal deriva de


FormsApplicationActivity, definida em
Xamarin.Forms.Platform.Android. Veja dentro do método
OnCrete a chamada ao método Forms.Init, descrito
anteriormente. A instância da App do Hello é passada como
parâmetro para o LoadApplication, como mencionamos antes.

39
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação – PCL versus SAP
Nossa primeira aplicação foi criada no modo PCL, ou seja, uma
DLL é criada e referenciada em cada projeto de App. Essa é a
melhor maneira de trabalhar com o Xamarin.Forms, embora a
SAP também seja suportada.

Com o SAP é possível utilizar diretivas de compilação, para que


o compilador utilize determinado código apenas para uma
plataforma específica. Por exemplo, se utilizar o símbolo
“__IOS__”, o código será específico para os dispositivos da
Apple.

Tais diretivas não fazem sentido num projeto do tipo PCL,


porque ele é inteiramente independente de plataforma. Mas
também é possível chamar algo específico de uma plataforma
num projeto PCL usando, por exemplo, Device.OnPlatform.

O projeto do tipo PCL foi originalmente proposto para manter


código específico para várias versões da .NET. Sendo assim,
cada PCL particular contém flags que indicam qual plataforma é
suportada.

40
#Dominando o Xamarin.Forms

Xamarin.Forms
Primeira aplicação
O Xamarin.Forms fornece uma série de facilidades para facilitar
o layout sem que seja preciso realizar cálculos. A classe view
define duas propriedades chamadas HorizontalOptions e
VerticalOptions, que definem como a view é posicionada no seu
pai.

Essas propriedades são do tipo LayoutOption, que contém oito


opções:


Start

Center

End

Fill

StartAndExpand

CenterAndExpand

EndAndExpand

FillAndExpand

Altere o código da classe App do Hello para cada uma da opções


acima e veja como a tela se comporta.

41
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto
Numa App é muito comum trabalhar com texto. Crie um novo Projeto PCL e chame de Baskervilles.
No App.cs deixe o código da seguinte maneira:

namespace Baskervilles
{
public class App : Application
{
public App()
{
MainPage = new BaskervillesPage();
}

protected override void OnStart()


{
// Handle when your app starts
}

protected override void OnSleep()


{
// Handle when your app sleeps
}

protected override void OnResume()


{
// Handle when your app resumes
}
}
} 42
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto
Veja que não estamos criando uma página diretamente no construtor da App, mas apontando para
uma outra classe. Dessa forma, clique com o botão direito em cima do nome do projeto (na
Solution Explorer) e selecione a opção Add New Item. Escolha a opção Visual C# / Cross-Platform /
Code / Forms Content Page. Será criada uma nova classe derivada de ContentPage. Chame-a de
BaskervillesPage. O romance policial The Hound of the Baskervilles (em português, O Cão dos
Baskervilles) foi escrito por Sir Arthur Conan Doyle, tendo como protagonistas Sherlock Holmes e
Dr. Watson. Vamos pegar uma pequena parte desse romance em inglês e mostrar na tela.

43
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto
namespace Baskervilles
{
public class BaskervillesPage : ContentPage
{
public BaskervillesPage()
{
Content = new Label
{
VerticalOptions = LayoutOptions.Center,
Text =
"Mr. Sherlock Holmes, who was usually very late in " +
"the mornings, save upon those not infrequent " +
"occasions when he was up all night, was seated at " +
"the breakfast table. I stood upon the hearth-rug " +
"and picked up the stick which our visitor had left " +
"behind him the night before. It was a fine, thick " +
"piece of wood, bulbous-headed, of the sort which " +
"is known as a \u201CPenang lawyer.\u201D Just " +
"under the head was a broad silver band, nearly an " +
"inch across, \u201CTo James Mortimer, M.R.C.S., " +
"from his friends of the C.C.H.,\u201D was engraved " +
"upon it, with the date \u201C1884.\u201D It was " +
"just such a stick as the old-fashioned family " +
"practitioner used to carry\u2014dignified, solid, " +
"and reassuring."
};

Padding = new Thickness(5, Device.OnPlatform(20, 5, 5), 5, 5);


}
}
} 44
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto
Observe que foram utilizados códigos Unicode para abrir e fechar aspas (\u201C e \u201D). A
propriedade Padding foi configurada para 5 unidades ao redor da página para evitar que o texto
ultrapasse os limites. Além disso, a propriedade VerticalOptions foi configurada para centralizar o
texto de modo vertical na página.

45
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto
Brinque um pouco com as propriedades HorizontalOptions com as opções Start, Center ou End.
Trabalhe ainda com a propriedade HorizontalTextAlignment do Label e veja como esta funciona.
Use ainda a propriedade LineBreakMode com suas opções para quebrar ou truncar o texto. A classe
Label tem muitas opções para flexibilizar o texto.

46
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto – Cores
O Label por padrão mostrará a cor mais apropriada para o dispositivo em questão. É possível
alterar esse comportamento através de duas propriedades: TextColor e BackgroundColor. A
primeira faz parte do próprio Label. A segunda é herdade de VisualElement, o que significa que
Page e Layout também possuem uma propriedade BackgroundColor. Observe o exemplo:

class GreetingsPage : ContentPage


{
public GreetingsPage()
{
Content = new Label
{
Text = "Greetings, Xamarin.Forms!",
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
BackgroundColor = Color.Yellow,
TextColor = Color.Blue
};
}
}

47
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto – Cores
Veja que interessante. O Label está ocupando todo o espaço da tela. É o resultado de usar as
propriedades HorizontalTextAlignment e VerticalTextAlignment. E se quiséssemos o amarelo apenas
no fundo do Label, sem dar essa impressão que a tela é amarela?

48
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto – Cores
Neste caso deveríamos usar as propriedades HorizontalOptions e VerticalOptions. Observe o
exemplo. O resultado pode ser visto na página seguinte.

namespace Greetings
{
class GreetingsPage : ContentPage
{
public GreetingsPage()
{
Content = new Label
{
Text = "Greetings, Xamarin.Forms!",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
BackgroundColor = Color.Yellow,
TextColor = Color.Blue
};
}
}
}

49
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto – Cores
Aí está o resultado. Agora sim o fundo amarelo encontra-se apenas no Label. Tirou aquela
impressão que o fundo da tela era amarelo. No exemplo anterior, o fundo amarelo era do Label, é
bom que fique claro, mas o alinhamento dava a impressão que era o fundo da tela.

50
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto – Cores
O valor padrão de TextColor e BackgroundColor é Color.Default, que vai setar a cor padrão de
acordo com o dispositivo. A estrutura Color armazena as cores de duas maneiras:


Com os valores red, green, e blue (RGB) do tipo double, com o intervalo entre 0 e 1.

Com valores para hue, saturation, e luminosity do tipo double, com o intervalo entre 0 e 1.

Existe ainda um canal alfa (alpha chanel) na estrutura Color para trabalhar com graus de
opacidade. Uma propriedade somente-leitura “A” expõem esse valor que vai do 0 (transparente) ao
1 (opaco).

Crie um novo projeto ou use um existente e brinque um pouco com os seguintes métodos:


new Color(double grayShade)

new Color(double r, double g, double b)

new Color(double r, double g, double b, double a)

Color.FromRgb(double r, double g, double b)

Color.FromRgb(int r, int g, int b)

Color.FromRgba(double r, double g, double b, double a)

Color.FromRgba(int r, int g, int b, int a)

Color.FromHsla(double h, double s, double l, double a)

51
#Dominando o Xamarin.Forms

Xamarin.Forms
Dominando o Texto – Cores
Color ainda disponibiliza 17 campos com nomes de cores que podem ser utilizados facilmente,
conforme tabela abaixo. Cuidado quando trabalhar com cores! Não tente criar uma App que se
pareça igual em todos os dispositivos criando seu próprio padrão. Leve em conta a experiência do
usuário. Aliás, LEVE MUITO EM CONTA A EXPERIÊNCIA DO USUÁRIO. No que for possível, siga o
padrão do dispositivo.

52
#Dominando o Xamarin.Forms

Xamarin.Forms
Esquema de Cores da Aplicação
É possível alterar o esquema de cores de toda a aplicação.

No caso do Android, basta alterar o arquivo AndroidManifest.xml que fica na pasta properties.
Normalmente esse arquivo tem o seguinte conteúdo:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="15" />
<application></application>
</manifest>

Para que a app Android apresente o texto preto num fundo branco, basta adicionar o seguinte
atributo à tag application:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="15" />
<application android:theme="@style/android:Theme.Holo.Light"></application>
</manifest>

53
#Dominando o Xamarin.Forms

Xamarin.Forms
Esquema de Cores da Aplicação
No caso das aplicações Windows é preciso alterar o arquivo App.xaml. Segue um arquivo desses
padrão para um projeto UWP:

<Application
x:Class="Greetings.UWP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Greetings.UWP"
RequestedTheme="Light">

</Application>

Observe o atributo RequestedTheme. Da forma como está definido a aplicação vai mostrar texto
preto sobre fundo branco. Se o atributo for alterado para “Dark” teremos fundo preto e texto
branco. Remova o atributo RequestedTheme caso queira permitir que o usuário determine a cor do
esquema.

54
#Dominando o Xamarin.Forms

Xamarin.Forms
Fontes
Por padrão, o Label usa um sistema de fontes definido por cada plataforma, mas existem diversas
propriedades que permitem alterar esse comportamento. As duas únicas classes que tem esse
comportamento são: Label e Button.

As propriedades que permitem a alteração da fonte são as seguintes:


FontFamily do tipo string. Permite configurar a família da fonte.

FontSize do tipo double. Permite configurar o tamanho da fonte.

FontAttributes. Uma enumeração com três membros: None, Bold, e Italic.

Observe o exemplo:

class GreetingsPage : ContentPage


{
public GreetingsPage()
{
Content = new Label
{
Text = "Greetings, Xamarin.Forms!",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
FontAttributes = FontAttributes.Bold | FontAttributes.Italic
};
}
} 55
#Dominando o Xamarin.Forms

Xamarin.Forms
Fontes
O resultado pode ser visto abaixo nas três plataformas.

56
#Dominando o Xamarin.Forms

Xamarin.Forms
Fontes – Texto Formatado
O Label em uma propriedade chamada FormattedText, que é do tipo FormattedString, que possui a
propriedade Spans do tipo Ilist<Span>, ou seja, uma coleção de objetos Span. Cada Span é um
pedaço formatado do texto, que é governado por seis propriedades:


Text

FontFamily

FontSize

FontAttributes

ForegroundColor

BackgroundColor

Observe o exemplo na página seguinte.

57
#Dominando o Xamarin.Forms

Xamarin.Forms
Fontes – Texto Formatado
public VariableFormattedTextPage()
{
FormattedString formattedString = new FormattedString();
formattedString.Spans.Add(new Span
{
Text = "I "
});
formattedString.Spans.Add(new Span
{
Text = "love",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
FontAttributes = FontAttributes.Bold
});
formattedString.Spans.Add(new Span
{
Text = " Xamarin.Forms!"
});
Content = new Label
{
FormattedText = formattedString,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
};
}

58
#Dominando o Xamarin.Forms

Xamarin.Forms
Fontes – Texto Formatado
É possível também fazer da seguinte maneira:

public VariableFormattedTextPage()
{
Content = new Label
{
FormattedText = new FormattedString
{
Spans =
{
new Span
{
Text = "I "},
new Span
{
Text = "love",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
FontAttributes = FontAttributes.Bold
},
new Span
{
Text = " Xamarin.Forms!"
}
}
},
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) 59
};
}
#Dominando o Xamarin.Forms

Xamarin.Forms
Fontes – Texto Formatado
Veja o resultado:

60
#Dominando o Xamarin.Forms

Xamarin.Forms
Layouts – Introdução
A classe ContentPage contém uma propriedade chamada Content do tipo View que você pode setar
para um objeto. Para mostrar múltiplas Views é preciso configurar Content para a instância de uma
classe que pode ter múltiplos filhos do tipo View.

Existem quatro classes que herdam de Layout<View>, que podem ter múltiplos filhos do tipo View:

AbsoluteLayout
Grid
RelativeLayout
StackLayout

Cada uma delas arruma seus filhos de uma maneira característica.

61
#Dominando o Xamarin.Forms

Xamarin.Forms
Layouts – StackLayout
O StackLayout organiza seus filhos numa pilha (stack). Ele define apenas
duas propriedades:


Orientation do tipo StackOrientation, uma enumeração que tem dois
membros: Vertical (padrão) e Horizontal.

Spacing do tipo double, iniciado por padrão com o valor 6.0.

Que tal mostrar os nomes das cores na tela? O StackLayout seria ideal
para isso. Observe o código a seguir:

class ColorLoopPage : ContentPage


{
public ColorLoopPage()
{
var colors = new[]
{
new { value = Color.White, name = "White" },
new { value = Color.Silver, name = "Silver" },
new { value = Color.Gray, name = "Gray" },
new { value = Color.Black, name = "Black" },
new { value = Color.Red, name = "Red" },
new { value = Color.Maroon, name = "Maroon" },
new { value = Color.Yellow, name = "Yellow" },
new { value = Color.Olive, name = "Olive" },

62
#Dominando o Xamarin.Forms

Xamarin.Forms
Layouts – StackLayout
new { value = Color.Lime, name = "Lime" },
new { value = Color.Green, name = "Green" },
new { value = Color.Aqua, name = "Aqua" },
new { value = Color.Teal, name = "Teal" },
new { value = Color.Blue, name = "Blue" },
new { value = Color.Navy, name = "Navy" },
new { value = Color.Pink, name = "Pink" },
new { value = Color.Fuchsia, name = "Fuchsia" },
new { value = Color.Purple, name = "Purple" }
};
StackLayout stackLayout = new StackLayout();
foreach (var color in colors)
{
stackLayout.Children.Add(
new Label
{
Text = color.name,
TextColor = color.value,
FontSize = Device.GetNamedSize(NamedSize.Large,
typeof(Label))
});
}
Padding = new Thickness(5, Device.OnPlatform(20, 5, 5), 5, 5);
Content = stackLayout;
}
}

63
#Dominando o Xamarin.Forms

Xamarin.Forms
Layouts – StackLayout
O resultado pode ser visto na imagem abaixo.

64
#Dominando o Xamarin.Forms

Xamarin.Forms
Layouts – StackLayout
Ficou interessante. Mas, se a quantidade de cores for maior que a altura
da tela, não tem como deslizar (ou navegar) pelas cores. Isso ocorre
porque o StackLayout não contém um recurso de Scrool automático. Para
isso teremos que usar um elemento chamado ScrollView.

Basta instanciar um ScrollView e adicionar o StackLayout como seu


Content. Observe o trecho de código modificado.

De:

Padding = new Thickness(5, Device.OnPlatform(20, 5, 5), 5, 5);


Content = stackLayout;

Para:

Padding = new Thickness(5, Device.OnPlatform(20, 5, 5), 5, 5);


Content = new ScrollView
{
Content = stackLayout
};

65
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView
Existem duas Views retangulares que são excelentes para apresentar dados.

A BoxView é um retângulo preenchido. Ela deriva de View e define uma propriedade Color com o
valor padrão como transparente.

O Frame exibe uma borda retangular ao redor do seu conteúdo. Deriva de Layout através e
ContentView, de onde herda a propriedade Content. O conteúdo de um Frame pode ser uma
simples view ou um layout contendo um conjunto de views. Através do VisualElement, o Frame
herda a propriedade BackgroundColor que é branca no iPhone e transparente no Android e no
Windows Phone.

O Frame herda a propriedade Padding do Layout e a inicializa com 20 unidades para todos os lados.
O próprio Frame define a propriedade HasShadow, que é “true” por padrão, mas é exibida apenas
nos dispositivos com iOS. Define ainda a propriedade OutlineColor que é transparente por padrão.
OutlineColor não afeta a shadow no iOS.

Vejamos como ficaria um Label como conteúdo de um Frame.

66
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView
public class FramedTextPage : ContentPage
{
public FramedTextPage()
{
Padding = new Thickness(20);
Content = new Frame
{
OutlineColor = Color.Accent,
Content = new Label
{
Text = "I've been framed!",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
}
};
}
}

O Label está centralizado no Frame, mas o Frame ocupa todo o espaço da página. Não dá pra ver
claramente que existe um Frame. Observe nas imagens a seguir.

67
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView

68
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView
Como fazer para deixar o Frame contornando apenas o texto? Vamos trabalhar com as
propriedades HorizontalOptions e VerticalOptions. Ambas serão configuradas para
LayoutOptions.Center.

public class FramedTextPage : ContentPage


{
public FramedTextPage()
{
Padding = new Thickness(20);
Content = new Frame
{
OutlineColor = Color.Accent,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
Content = new Label
{
Text = "I've been framed!",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
}
};
}
}

Observe o resultado nas imagens a seguir.

69
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView

70
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView
Criar uma BoxView é muito simples. Observe o código abaixo. Brinque um pouco com as cores e
tamanhos da caixa.

public class SizedBoxViewPage : ContentPage


{
public SizedBoxViewPage()
{
BackgroundColor = Color.Pink;
Content = new BoxView
{
Color = Color.Navy,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
WidthRequest = 200,
HeightRequest = 100
};
}
}

Observe o resultado nas imagens a seguir.

71
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView

72
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView
Que tal unir Frame e BoxView para mostrar as cores?! Vamos lá.

class ColorBlocksPage : ContentPage


{

View CreateColorView(Color color, string name)


{
return new Frame
{
OutlineColor = Color.Accent,
Padding = new Thickness(5),
Content = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Spacing = 15,
Children =
{
new BoxView
{
Color = color
},
new Label
{
Text = name,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),

73
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView
FontAttributes = FontAttributes.Bold,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.StartAndExpand
},
new StackLayout
{
Children =
{
new Label
{
Text = String.Format("{0:X2}-{1:X2}-{2:X2}",
(int)(255 * color.R),
(int)(255 * color.G),
(int)(255 * color.B)),
VerticalOptions = LayoutOptions.CenterAndExpand,
IsVisible = color != Color.Default
},
new Label
{
Text = String.Format("{0:F2}, {1:F2}, {2:F2}",
color.Hue,
color.Saturation,
color.Luminosity),
VerticalOptions = LayoutOptions.CenterAndExpand,
IsVisible = color != Color.Default
}
},
HorizontalOptions = LayoutOptions.End 74
}
#Dominando o Xamarin.Forms

Xamarin.Forms
Frame e BoxView
Veja o resultado logo abaixo.

75
#Dominando o Xamarin.Forms

Xamarin.Forms
Lidando com Tamanhos
Existem alguns tamanhos padrões que são definidos por diversos elementos. Por exemplo:


A barra de status do iOS tem a altura definida como 20.

O tamanho padrão da uma BoxView é 40 (altura e largura).

O tamanho padrão do Padding para o Frame é 20.

O padrão da propriedade Spacing do StackLayout é 6.

Existem muitas plataformas e muitos dispositivos. Você deve se preocupar em saber cada tamanho
e tentar redimensionar os tamanhos dos objetos e das fontes? Bom, pode ser desgastante tentar
fazer isso. É melhor confiar nos padrões definidos pelo Xamarin.Forms e por cada plataforma.

Mas, e se for preciso saber o tamanho da tela para configurar diretamente o tamanho de
determinado objeto? Uma tela é um retângulo que é mapeado como um array de pixels. O pixel é o
menor elemento num dispositivo de exibição.

Não vamos entrar em muitos detalhes, mas podemos dizer que existem vários conceitos
envolvidos: tamanho do pixel, tamanho diagonal da tela (em polegadas), densidade dos pixels,
pixels por ponto, tamanho do ponto, pontos por polegada, etc.

Quando se pergunta a resolução de uma tela, costuma-se responder da seguinte maneira:


800x600, por exemplo. O 800 se refere à largura da tela e 600 se refere à altura (em pixels).

76
#Dominando o Xamarin.Forms

Xamarin.Forms
Lidando com Tamanhos
O código a seguir exibe o tamanho da tela do dispositivo:

public class WhatSizePage : ContentPage


{
Label label;
public WhatSizePage()
{
label = new Label
{
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
Content = label;
SizeChanged += OnPageSizeChanged;
}
void OnPageSizeChanged(object sender, EventArgs args)
{
label.Text = String.Format("{0} \u00D7 {1}", Width, Height);
}
}

Observe o resultado nas imagens a seguir.

77
#Dominando o Xamarin.Forms

Xamarin.Forms
Lidando com Tamanhos

78
#Dominando o Xamarin.Forms

Xamarin.Forms
Lidando com Tamanhos
Em relação às fontes, o Label e o Button possuem a propriedade FontSize, que serve para
configurar o tamanho da fonte. Em muitos casos é melhor trabalhar com Device.GetNamedSize que
permite especificar um membro da enumeração NamedSize: Default, Micro, Small, Medium ou
Large. Observe no exemplo abaixo (o exemplo usa a opção Large):

class GreetingsPage : ContentPage


{
public GreetingsPage()
{
Content = new Label
{
Text = "Greetings, Xamarin.Forms!",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
FontAttributes = FontAttributes.Bold | FontAttributes.Italic
};
}
}

É possível realizar alguns cálculos com base no tamanho da tela, na resolução, etc para configurar
diretamente o tamanho de uma fonte. Prefira, no entanto, usar o padrão para evitar dores de
cabeça.

79
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
Os componentes gráficos que aparecem para o usuário, as views, podem ser divididos em dois
grupos: aqueles que apresentam dados para o usuário, como um Label e aqueles que obtém uma
entrada através da interação com o usuário, como um Button.

O Button é a forma de o usuário solicitar alguma coisa para a aplicação, de enviar um comando,
uma ação.

Um Button no Xamarin.Forms exibe texto e pode ou não vir acompanhado de uma imagem.
Quando o usuário seleciona um botão, o mesmo muda sua aparência para dar um feedback para o
usuário. Quando o dedo do usuário solta o botão, um evento é disparado (Clicked). Esse evento
possui dois argumentos:


O primeiro argumento é o objeto que dispara o evento. Para o manipulador (handler) do Clicked,
o objeto em questão é o botão que acabou de ser pressionado.

O segundo argumento algumas vezes fornece mais informações sobre o evento. No caso do
evento Clicked do Button, o segundo argumento é um EventArgs que não fornece informações
adicionais.

Vamos analisar um primeiro código onde cada vez que há um clique no botão, um Label é
adicionado num StackLayout exibindo a hora em que o botão foi clicado.

80
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
public class ButtonLoggerPage : ContentPage
{
StackLayout loggerLayout = new StackLayout();
public ButtonLoggerPage()
{
// Create the Button and attach Clicked handler.
Button button = new Button
{
Text = "Log the Click Time"
};
button.Clicked += OnButtonClicked;
this.Padding = new Thickness(5, Device.OnPlatform(20, 0, 0), 5, 0);
// Assemble the page.
this.Content = new StackLayout
{
Children =
{
button,
new ScrollView
{
VerticalOptions = LayoutOptions.FillAndExpand,
Content = loggerLayout
}
}
};
}

81
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
void OnButtonClicked(object sender, EventArgs args)
{
// Add Label to scrollable StackLayout.
loggerLayout.Children.Add(new Label
{
Text = "Button clicked at " + DateTime.Now.ToString("T")
});
}
}

O programa é de fácil assimilação. Observe o resultado na página seguinte.

82
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões

83
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
O Button fornece várias propriedades para customizar sua aparência. Dentre elas:


FontFamily do tipo string

FontSize do tipo double

FontAttributes do tipo FontAttributes

TextColor do tipo Color (o padrão é Color.Default)

BorderColor do tipo Color (o padrão é Color.Default)

BorderWidth do tipo double (o padrão é 0)

BorderRadius do tipo double (o padrão é 5)

Image

Além dessas, o Button herda a propriedade BackgroundColor de VisualElement e HorizontalOptions


and VerticalOptions da View.

Às vezes é interessante compartilhar determinado método com vários botões. Imagine uma
calculadora com 10 botões. Ter 10 método, um para cada botão, pode não ser a saída mais
elegante. Que tal um método só?

Observe o código a seguir, que é bem parecido com o anterior, sendo que neste existe um botão
para remover uma das entradas da pilha. Temos dois botões compartilhando o mesmo método.

84
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
public class TwoButtonsPage : ContentPage
{
Button addButton, removeButton;
StackLayout loggerLayout = new StackLayout();
public TwoButtonsPage()
{
// Create the Button views and attach Clicked handlers.
addButton = new Button
{
Text = "Add",
HorizontalOptions = LayoutOptions.CenterAndExpand
};
addButton.Clicked += OnButtonClicked;
removeButton = new Button
{
Text = "Remove",
HorizontalOptions = LayoutOptions.CenterAndExpand,
IsEnabled = false
};
removeButton.Clicked += OnButtonClicked;
this.Padding = new Thickness(5, Device.OnPlatform(20, 0, 0), 5, 0);
// Assemble the page.
this.Content = new StackLayout
{
Children =
{

85
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
new StackLayout
{
Orientation = StackOrientation.Horizontal,
Children =
{
addButton,
removeButton
}
},
new ScrollView
{
VerticalOptions = LayoutOptions.FillAndExpand,
Content = loggerLayout
}
}
};
}

void OnButtonClicked(object sender, EventArgs args)


{
Button button = (Button)sender;
if (button == addButton)
{

86
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
// Add Label to scrollable StackLayout.
loggerLayout.Children.Add(new Label
{
Text = "Button clicked at " + DateTime.Now.ToString("T")
});
}
else
{
// Remove topmost Label from StackLayout.
loggerLayout.Children.RemoveAt(0);
}
// Enable "Remove" button only if children are present.
removeButton.IsEnabled = loggerLayout.Children.Count > 0;
}

Observe que o método OnButtonClicked verifica qual botão o chamou. Se for o botão addButton,
ele adiciona o texto na tela. Se não, ele remove um item. E se não houver nenhum elemento, o
que vai ocorrer quando o usuário clicar no botão para remover? Uma exceção. Neste caso, o ideal é
verificar se existem itens para ser removidos, caso não existam, desabilite o botão através da
propriedade IsEnabled.

Em alguns casos será melhor trabalhar com a propriedade StyleId, que é do tipo String e pertence
à classe Element. O objetivo dessa propriedade é identificar Views.

87
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
É possível trabalhar com funções anônimas lambda. Observe como fica o código.

public class ButtonLambdasPage : ContentPage


{
public ButtonLambdasPage()
{
// Number to manipulate.
double number = 1;
// Create the Label for display.
Label label = new Label
{
Text = number.ToString(),
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
// Create the first Button and attach Clicked handler.
Button timesButton = new Button
{
Text = "Double",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
HorizontalOptions = LayoutOptions.CenterAndExpand
};
timesButton.Clicked += (sender, args) =>
{
number *= 2;
label.Text = number.ToString();
}; 88
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
// Create the second Button and attach Clicked handler.
Button divideButton = new Button
{
Text = "Half",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
HorizontalOptions = LayoutOptions.CenterAndExpand
};
divideButton.Clicked += (sender, args) =>
{
number /= 2;
label.Text = number.ToString();
};
// Assemble the page.
this.Content = new StackLayout
{
Children =
{
label,
new StackLayout
{
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.CenterAndExpand,
Children =
{
timesButton,
divideButton
}
} 89
}
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões

90
#Dominando o Xamarin.Forms

Xamarin.Forms
Botões
Observe que cada botão possui uma função lambda anexada. A desvantagem de usar funções
lambda é que o código não pode ser compartilhado com múltiplas views. Poder até pode, mas
envolve reflexão, o que complica um pouco as coisas.

E se você quisesse armazenar um dado transiente? Dado transiente é aquele que não é
armazenado num banco de dados. Um dado que está na tela, mas que pode ser útil recuperar caso
o usuário saia da aplicação e retorne.

91
#Dominando o Xamarin.Forms

Xamarin.Forms
Dados Transientes
A classe Application contém duas facilidades para que a aplicação salve e restaure dados:


A propriedade Properties é um dicionário com chaves “string” e items “object”. O conteúdo desse
dicionário é automaticamente salvo antes da aplicação ser encerrada. O conteúdo salvo ficará
disponível na próxima vez que a aplicação for iniciada.

A classe Application possui ainda três métodos virtuais protected: OnStart, OnSleep e
OnResume. A classe App do Xamarin.Forms sobrescreve esses métodos. Tais métodos ajudam a
trabalhar com os eventos do ciclo de vida da aplicação.

Para usar essas facilidades, é preciso identificar qual tipo de informação sua aplicação precisa
salvar para ser restaurada posteriormente. Geralmente é uma combinação de configurações
(setings), tais como cores, tamanho de fontes, etc e dados transientes, como alguma coisa que o
usuário digitou ou selecionou na tela. As configurações salvas normalmente se aplicam a toda a
aplicação, enquanto os dados transientes são referentes a determinada página.

E como fazer para ter acesso à classe Application? Ela fornece uma propriedade estática chamada
Current, que retorna uma instância da aplicação corrente. Observe como armazenar o texto de um
label:

Application.Current.Properties["displayLabelText"] = displayLabel.Text;

92
#Dominando o Xamarin.Forms

Xamarin.Forms
Dados Transientes
E para recuperar o texto do label? Qual seria o procedimento? Basta colocar o seguinte código no
construtor:

IDictionary<string, object> properties = Application.Current.Properties;


if (properties.ContainsKey("displayLabelText"))
{
displayLabel.Text = properties["displayLabelText"] as string;
backspaceButton.IsEnabled = displayLabel.Text.Length > 0;
}

Pronto. Resolvido. Salvamos e recuperamos o dado. Mas, às vezes, é preciso que a aplicação
interaja com o dicionário Properties de uma maneira mais estruturada. Aí que entram os eventos
do ciclo de vida. São aqueles três métodos fornecidos pela classe App.

93
#Dominando o Xamarin.Forms

Xamarin.Forms
Dados Transientes
O mais importante é o OnSleep.

public class App : Application


{
public App()
{

}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}

Normalmente uma aplicação entra nesse modo quando o usuário não interage mais com ela e ela
fica inativa, independente de qualquer processo de fundo que esteja ocorrendo.

94
#Dominando o Xamarin.Forms

Xamarin.Forms
Dados Transientes
A partir do modo Sleep (dormindo) a aplicação pode ser recuperada, ou resumida. O termo em
inglês é “resumed” e daí vem o evento OnResume.

Quando uma aplicação Xamarin.Forms está em execução, a forma mais fácil de disparar o evento
OnSleep é pressionar o botão “home” do dispositivo. Daí, ao pressionar novamente o ícone da
aplicação, a mesma vai disparar o evento OnResume. Em dispositivos Windows Phone, é possível
ter o mesmo efeito pressionando o botão Back.

Se você estiver usando tais métodos para salvar e restaurar dados apenas, não precisa tratar o
método OnResume. Quando a aplicação chama o método OnResume, o sistema operacional
automaticamente restaura o conteúdo e o estado da aplicação. Se desejar, você pode usar o
OnResume para limpar o conteúdo do dicionário Properties. Se seu programa tem uma conexão
com um webservice, por exemplo, o OnResume poderia ser utilizado para restabelecer essa
conexão.

Quando a aplicação é iniciada, a primeira oportunidade de executar algum código na PCL é o


construtor da classe App. Nesse momento o dicionário Properties acabou de ser preenchido.
Geralmente, o próximo código que é executado é o do construtor da primeira página da aplicação,
instanciado pelo construtor de App. A chamada ao OnStart segue esse fluxo. Um método
sobrescrito chamado OnAppearing é chamado na classe da página. É possível recuperar dados em
qualquer momento durante o processo de inicialização.

95
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Até agora vimos como escrever os programas diretamente no C#. É possível criar uma aplicação
Xamarin.Forms inteira utilizando apenas o C#. No entanto, temos uma alternativa interessante
para desenhar as telas da aplicação: o XAML.

O XAML é uma linguagem de marcação declarativa utilizada para instanciar e inicializar objetos.
Utilizar o XAML traz várias vantagens, dentre elas, utilizar várias pessoas na mesma equipe para
criar a aplicação: programadores e designers. Enquanto o programador trabalha no código em C#,
o designer trabalha nas telas usando o XAML.

É muito fácil criar vinculações (bindings) dentro do XAML, apontando para objetos, listas e fontes
de dados definidos na aplicação em C#.

Uma coisa que pode lhe deixar preocupado ou até mesmo chateado é que o Xamarin.Forms não
possui uma ferramenta de design para o XAML. Dessa forma, é preciso fazer tudo “na mão”.
Quando criamos aplicações para o WPF, o XAML apresenta os dados diretamente na tela, de forma
visual e isso facilita muito a nossa vida. Mas, será mesmo uma falta tão grande para aplicações
mobile? Tais aplicações costumam ser bem menos complexas que aplicações desktop. Além disso,
você poderá utilizar o recurso Previewer que permite ver o layout da aplicação em tempo real sem
precisar carregá-la num dispositivo ou emulador.

A seguir segue a imagem do Previewer e o trecho de um código em C# instanciando e inicializando


um Label e o seu equivalente em XAML.

96
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML

97
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Código em C#:

new Label
{
Text = "Hello from Code!",
IsVisible = true,
Opacity = 0.75,
HorizontalTextAlignment = TextAlignment.Center,
VerticalOptions = LayoutOptions.CenterAndExpand,
TextColor = Color.Blue,
BackgroundColor = Color.FromRgb(255, 128, 128),
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
FontAttributes = FontAttributes.Bold | FontAttributes.Italic
};

Código em XAML:

<Label Text="Hello from XAML!"


IsVisible="True"
Opacity="0.75"
HorizontalTextAlignment="Center"
VerticalOptions="CenterAndExpand"
TextColor="Blue"
BackgroundColor="#FF8080"
FontSize="Large"
FontAttributes="Bold,Italic" />
98
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
E onde este Label está inserido? Onde a página é definida? E o layout? Observe o código fonte
completo do XAML em questão logo abaixo. Perceba que temos uma ContentPage e em seu
conteúdo (Content) temos um StackLayout com um filho (Children) que é o Label.

<?xml version="1.0" encoding="utf-8" ?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CodePlusXaml.CodePlusXamlPage">
<ContentPage.Content>
<StackLayout>
<StackLayout.Children>
<Label Text="Hello from XAML!"
IsVisible="True"
Opacity="0.75"
HorizontalTextAlignment="Center"
VerticalOptions="CenterAndExpand"
TextColor="Blue"
BackgroundColor="#FF8080"
FontSize="Large"
FontAttributes="Bold,Italic" />
</StackLayout.Children>
</StackLayout>
</ContentPage.Content>
</ContentPage>

99
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Observe o código abaixo em C#:

new Frame
{
OutlineColor = Color.Accent,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
Content = new Label
{
Text = "Greetings, Xamarin.Forms!"
}
};

Como converter o código acima para XAML? Como colocar um Label dentro de um Frame? Veja
logo a seguir:

<Frame OutlineColor="Accent"
HorizontalOptions="Center"
VerticalOptions="Center">
<Frame.Content>
<Label Text="Greetings, Xamarin.Forms!" />
</Frame.Content>
</Frame>

100
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
No exemplo anterior, Frame e Label são objetos C# expressos como elementos XML. Eles são
chamados de object elements.

OutlineColor, HorizontalOptions, VerticalOptions e Text são propriedades C# expressas como


atributos XML. Elas são chamadas de property attributes.

Frame.Content é uma propriedade C# expressa como um elemento XML. É conhecida como


property element.

Também é possível fazer da seguinte maneira, utilizando outra sintaxe:

<Frame HorizontalOptions="Center">
<Frame.VerticalOptions>
Center
</Frame.VerticalOptions>
<Frame.OutlineColor>
Accent
</Frame.OutlineColor>
<Frame.Content>
<Label>
<Label.Text>
Greetings, Xamarin.Forms!
</Label.Text>
</Label>
</Frame.Content>
</Frame> 101
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Abaixo podemos ver um código com vários StackLayout, sendo que cada filho é um StackLayout.

<StackLayout>
<StackLayout.Children>
<StackLayout Orientation="Horizontal">
<StackLayout.Children>
<BoxView Color="Red" />
<Label Text="Red"
VerticalOptions="Center" />
</StackLayout.Children>
</StackLayout>
<StackLayout Orientation="Horizontal">
<StackLayout.Children>
<BoxView Color="Green" />
<Label Text="Green"
VerticalOptions="Center" />
</StackLayout.Children>
</StackLayout>
<StackLayout Orientation="Horizontal">
<StackLayout.Children>
<BoxView Color="Blue" />
<Label Text="Blue"
VerticalOptions="Center" />
</StackLayout.Children>
</StackLayout>
</StackLayout.Children>
</StackLayout>
102
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
O objetivo do código anterior é mostrar as cores. Temos um BoxView com a cor e um Label com o
nome da cor. Imagine fazer isso com 100 cores! O código iria ficar gigante! A manutenção seria
sofrível. Em casos assim é melhor usar o código C#, pois o XAML não possui loops.

Sempre que o código XAML estiver ficando gigante e for preciso utilizar recursos comuns do C#,
como um loop, pare e considere fazer parte do código em questão diretamente em C#.

103
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Para adicionar uma página XAML ao projeto, proceda da seguinte maneira:


Crie um novo projeto Xamarin.Forms do tipo PCL.

Clique com o botão direito no nome do projeto PCL lá no Solution Explorer e selecione Add / New
Item. Na janela que vai surgir, selecione a opção Forms Xaml Page, conforme imagem abaixo.

104
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Serão criados dois arquivos. Como deixamos o nome “Page1.cs”, os arquivos criados serão os
seguintes:


Page1.xaml: conterá o código XAML.

Page1.xaml.cs: o arquivo C# referente ao arquivo XAML.

Tais arquivos contribuem para uma classe chamada Page1 que deriva de ContentPage. Observe o
código C#:

public partial class Page1 : ContentPage


{
public Page1()
{
InitializeComponent();
}
}

Veja que a assinatura contém uma palavra “partial” que indica que ela é apenas parte da definição
da classe Page1.

Vejamos agora o código XAML.

105
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Vejamos agora o código XAML.

<?xml version="1.0" encoding="utf-8" ?>


<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CodePlusXaml.Page1">
<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>

O elemento raiz é ContentPage, que é de onde a classe Page1 deriva. Essa tag inicia com duas
declarações de namespace, ambas URIs. Não existe nada nesses endereços web. Tais URIs apenas
indicam quem é o dono do namespace e para qual função ele serve.

Temos então o atributo x:Class. O “x” é o prefixo mais utilizado para esse namespace. Só pode
aparece no elemento raiz (root) do arquivo XAML. Essa especificação “x:Class” indica que a classe
“Page1” deriva de ContentPage. É a mesma informação que temos lá no arquivo C#:
Page1.xaml.cs.

Que tal colocar alguns elementos nesse XAML. Vamos incluir um StackLayout e um Label como
conteúdo de ContentPage. Veja a seguir como fica o código.

106
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CodePlusXaml.Page1">
<ContentPage.Content>
<StackLayout>
<StackLayout.Children>
<Label Text="Hello from XAML!"
IsVisible="True"
Opacity="0.75"
HorizontalTextAlignment="Center"
VerticalOptions="CenterAndExpand"
TextColor="Blue"
BackgroundColor="#FF8080"
FontSize="Large"
FontAttributes="Bold,Italic" />
</StackLayout.Children>
</StackLayout>
</ContentPage.Content>
</ContentPage>

Como fazer agora para deixar essa página como principal para nossa aplicação? Acesse a classe
App.cs e altere o construtor apontando para nossa página:

public App()
{
MainPage = new Page1();
} 107
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
É possível realizar algumas configurações com base na plataforma diretamente no código XAML.
Por exemplo, ao escrever um programa qualquer que preencha a tela inteira, teremos um
problema com o iOS, que tem sua barra de status na parte superior da tela. Para resolver essa
situação é preciso configurar a propriedade Padding. Observe como fazer isso diretamente no
XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ScaryColorList.ScaryColorListPage"
Padding="0, 20, 0, 0">
<ContentPage.Content>

</ContentPage.Content>
</ContentPage>

O problema da solução acima é que o Padding será ajustado para todas as plataformas. Observe
que são quatro opções para o Padding, seguindo a seguinte ordem: Esquerda (left), Acima (top),
Direita (right) e abaixo (bottom).

Mas tem como realizar tal configuração por plataforma. Observe a seguir.

108
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ScaryColorList.ScaryColorListPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<ContentPage.Content>

</ContentPage.Content>
</ContentPage>

Observe que o OnPlatform foi configurado apenas para o iOS. Neste caso a tela será configurada
apenas para essa plataforma. Numa aplicação que exibe uma coleção de cores o resultado pode ser
visto na página seguinte. Apenas no caso do iOS foi aplicado o Padding.

109
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML

110
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Você pode configurar o texto num Label de três maneiras:

<Label VerticalOptions="CenterAndExpand"
Text="Texto simples numa TAG label fechada nela mesma." />

<Label VerticalOptions="CenterAndExpand">
<Label.Text>
Texto simples usando a propriedade Label.Text.
</Label.Text>
</Label>

<Label VerticalOptions="CenterAndExpand">
Texto simples na TAG label com fechamento explícito.
</Label>

É importante observar que vai ocorrer um “trim” nesse texto, ou seja, serão removidos espaços em
branco do início e fim do texto. Os espaços em branco no meio do texto permanecerão.

111
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Em alguns casos você vai querer formatar partes do texto. Para isso, utilize Label.FormattedText
em conjunto com FormattedString. Observe:

<Label VerticalOptions="CenterAndExpand">
<Label.FormattedText>
<FormattedString>
<Span Text="Uma simples linha com " />
<Span Text="negrito" FontAttributes="Bold" />
<Span Text=" e " />
<Span Text="itálico" FontAttributes="Italic" />
<Span Text=" e texto " />
<Span Text="grande." FontSize="Large" />
</FormattedString>
</Label.FormattedText>
</Label>

Não esqueça que por trás do XAML existe código C# que pode manipular os elementos que estão
no XAML. Além disso, o código em XAML pode disparar eventos que estão definidos no código em
C#.

112
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
É possível passar argumentos para o construtor de um elemento em XAML. Embora não seja muito
usual, é bom saber como funciona. Para realizar tal tarefa é preciso utilizar x:Arguments com um
tipo base. Os tipos base são os seguintes:

x:Object
x:Boolean
x:Byte
x:Int16
x:Int32
x:Int64
x:Single
x:Double
x:Decimal
x:Char
x:String
x:TimeSpan
x:Array
x:DateTime

Por exemplo, Color possui alguns construtores. Um deles aguarda três argumentos do tipo Double:
red (vermelho), green (verde) e blue (azul). Observe o exemplo onde utilizamos Color e enviamos
três parâmetros para seu construtor diretamente no código XAML.

113
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ParameteredConstructorDemo.ParameteredConstructorDemoPage">
<StackLayout>
<BoxView WidthRequest="100"
HeightRequest="100"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<BoxView.Color>
<Color>
<x:Arguments>
<x:Double>1</x:Double>
<x:Double>0</x:Double>
<x:Double>0</x:Double>
</x:Arguments>
</Color>
</BoxView.Color>
</BoxView>
</StackLayout>
</ContentPage>

O número de argumentos precisa bater com a quantidade de argumentos de um dos construtores


do elemento selecionado.

114
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
É bom nomear os elementos do XAML para que seja possível manipulá-los no código C#. Para isso,
utilizamos o atributo x:Name. Observe.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlClock.XamlClockPage">
<StackLayout>
<Label x:Name="timeLabel"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="EndAndExpand" />
<Label x:Name="dateLabel"
HorizontalOptions="Center"
VerticalOptions="StartAndExpand" />
</StackLayout>
</ContentPage>

Agora é possível manipular os elementos de nomes timeLabel e dateLabe. O x:Name funciona


como uma variável. Observe como utilizar tais elementos no código C#:

115
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
namespace XamlClock
{
public partial class XamlClockPage
{
public XamlClockPage()
{
InitializeComponent();
Device.StartTimer(TimeSpan.FromSeconds(1), OnTimerTick);
}
bool OnTimerTick()
{
DateTime dt = DateTime.Now;
timeLabel.Text = dt.ToString("T");
dateLabel.Text = dt.ToString("D");
return true;
}
}
}

Observe como utilizamos timeLabel e dataLabel como variáveis normais do C#, setando sua
propriedade Text. Veja o resultado na página seguinte.

116
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML

117
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Saiba que os nomes que você fornece em x:Name são únicos, ou seja, você não pode dar o mesmo
nome para dois Labels. Isso pode se tornar um desafio se você for trabalhar com código específico
por plataforma. Observe o exemplo:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PlatformSpecificLabels.PlatformSpecificLabelsPage">
<OnPlatform x:TypeArguments="View">
<OnPlatform.iOS>
<Label Text="This is an iOS device"
HorizontalOptions="Center"
VerticalOptions="Center" />
</OnPlatform.iOS>
<OnPlatform.Android>
<Label Text="This is an Android device"
HorizontalOptions="Center"
VerticalOptions="Center" />
</OnPlatform.Android>
<OnPlatform.WinPhone>
<Label Text="This is an Windows device"
HorizontalOptions="Center"
VerticalOptions="Center" />
</OnPlatform.WinPhone>
</OnPlatform>
</ContentPage>

118
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
Veja que temos três Labels e cada um deles será visto em determinada plataforma. Se você utilizar
o código dessa maneira, o XAML vai instanciar e inicializar cada um dos Labels. Veja também que
os Labels ainda não possuem nome. E se você quiser manipulá-los no código em C#? Fornecer o
mesmo nome para os três não vai dar certo. Fornecer um nome para cada e manipular o código
dessa forma será sofrível!

A solução é trabalhar apenas a parte do código que precisa ser específica para a plataforma. Veja
como tratamos apenas a propriedade .Text no código a seguir, utilizando apenas um Label. Analise
o resultado na página seguinte.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PlatformSpecificLabels.PlatformSpecificLabelsPage">
<Label x:Name="deviceLabel"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label.Text>
<OnPlatform x:TypeArguments="x:String"
iOS="This is an iOS device"
Android="This is an Android device"
WinPhone="This is a Windows device" />
</Label.Text>
</Label>
</ContentPage>

119
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML

120
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
No código XAML você vai distribuir as views. Os eventos serão implementados no código C# que
está “por trás” do XAML. Na aplicação abaixo podemos ver um teclado numérico. Vejamos como
fica o XAML e a implementação em C# dessa aplicação.

121
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlKeypad.XamlKeypadPage">
<StackLayout VerticalOptions="Center"
HorizontalOptions="Center">
<Label x:Name="displayLabel"
Font="Large"
VerticalOptions="Center"
HorizontalTextAlignment="End" />
<Button x:Name="backspaceButton"
Text="&#x21E6;"
Font="Large"
IsEnabled="False"
Clicked="OnBackspaceButtonClicked" />
<StackLayout Orientation="Horizontal">
<Button Text="7" StyleId="7" Font="Large"
Clicked="OnDigitButtonClicked" />
<Button Text="8" StyleId="8" Font="Large"
Clicked="OnDigitButtonClicked" />
<Button Text="9" StyleId="9" Font="Large"
Clicked="OnDigitButtonClicked" />
</StackLayout>

122
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
<StackLayout Orientation="Horizontal">
<Button Text="4" StyleId="4" Font="Large"
Clicked="OnDigitButtonClicked" />
<Button Text="5" StyleId="5" Font="Large"
Clicked="OnDigitButtonClicked" />
<Button Text="6" StyleId="6" Font="Large"
Clicked="OnDigitButtonClicked" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Button Text="1" StyleId="1" Font="Large"
Clicked="OnDigitButtonClicked" />
<Button Text="2" StyleId="2" Font="Large"
Clicked="OnDigitButtonClicked" />
<Button Text="3" StyleId="3" Font="Large"
Clicked="OnDigitButtonClicked" />
</StackLayout>
<Button Text="0" StyleId="0" Font="Large"
Clicked="OnDigitButtonClicked" />
</StackLayout>
</ContentPage>

Temos vários botões, mas apenas dois métodos: OnDigitButtonClicked e


OnBackspaceButtonClicked. E como está o código C#? Veja a seguir que temos o construtor e os
dois métodos implementados. Muito simples!

123
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
public partial class XamlKeypadPage
{
App app = Application.Current as App;
public XamlKeypadPage()
{
InitializeComponent();
displayLabel.Text = app.DisplayLabelText;
backspaceButton.IsEnabled = displayLabel.Text != null &&
displayLabel.Text.Length > 0;
}
void OnDigitButtonClicked(object sender, EventArgs args)
{
Button button = (Button)sender;
displayLabel.Text += (string)button.StyleId;
backspaceButton.IsEnabled = true;
app.DisplayLabelText = displayLabel.Text;
}
void OnBackspaceButtonClicked(object sender, EventArgs args)
{
string text = displayLabel.Text;
displayLabel.Text = text.Substring(0, text.Length - 1);
backspaceButton.IsEnabled = displayLabel.Text.Length > 0;
app.DisplayLabelText = displayLabel.Text;
}
}

124
#Dominando o Xamarin.Forms

Xamarin.Forms
XAML
É possível responder aos toques do usuário na tela através dos gestures. O controle dos toques é
habilitado quando adicionamos o objeto à coleção GestureRecognizers. O código C# ficaria da
seguinte maneira:

BoxView boxView = new BoxView


{
Color = Color.Blue
};
TapGestureRecognizer tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += OnBoxViewTapped;
boxView.GestureRecognizers.Add(tapGesture);

TapGestureRecognizer também define a propriedade NumberOfTapsRequired com o valor padrão


“1”. Se for configurado para “2” implementa o duplo toque. No código XAML basta anexar o
TapGestureRecognizer numa view. Veja:

<BoxView Color="Blue">
<BoxView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnBoxViewTapped" />
</BoxView.GestureRecognizers>
</BoxView>

125
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API
Em determinados momentos será preciso fazer chamadas à API (Application Programming
Interface - Interface de Programação de Aplicação) para utilizar algum recurso do dispositivo. Por
exemplo, o Xamarin.Forms não dispõe de controle de som. Neste caso, é preciso fazer uma
chamada à API da plataforma. Vejamos como é possível utilizar a API em projetos SAP e PLC.
Vamos criar um projeto que exiba informações sobre a plataforma. Primeiramente um projeto SAP.
Observe o código XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PlatInfoSap1.PlatInfoSap1Page">
<StackLayout Padding="20">
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="Device Model:" />
<ContentView Padding="50, 0, 0, 0">
<Label x:Name="modelLabel"
FontSize="Large"
FontAttributes="Bold" />
</ContentView>
</StackLayout>
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="Operating System Version:" />
<ContentView Padding="50, 0, 0, 0">
<Label x:Name="versionLabel"
FontSize="Large"
FontAttributes="Bold" />
</ContentView>
</StackLayout> 126
</StackLayout>
</ContentPage>
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API
O código por trás desse XAML vai configurar a propriedade Text para modelLabel e versionLabel.
Como estamos trabalhando com um projeto SAP, podemos usar as diretivas: #if, #elif, #else, e
#endif com símbolos de compilação condicional para as três plataformas.


__IOS__ for iOS

__ANDROID__ for Android

WINDOWS_UWP for the Universal Windows Platform

WINDOWS_APP for Windows 8.1

WINDOWS_PHONE_APP for Windows Phone 8.1

A maneira de obter as informações sobre modelo e versão é diferente para cada plataforma:


Para o iOS, é preciso usar a classe UIDevice no namespace UIKit.

Para o Android, é preciso utilizar várias propriedades da classe Build no namespace Android.OS.

Nas plataformas Windows, é preciso usar a classe EasClientDeviceInformation no namespace
Windows.Security.ExchangeActiveSyncProvisioning.

Vamos ver então como ficar o código por trás do XAML.

127
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API
using System;
using Xamarin.Forms;

#if __IOS__
using UIKit;

#elif __ANDROID__
using Android.OS;

#elif WINDOWS_APP || WINDOWS_PHONE_APP || WINDOWS_UWP


using Windows.Security.ExchangeActiveSyncProvisioning;

#endif

namespace PlatInfoSap1
{
public partial class PlatInfoSap1Page : ContentPage
{
public PlatInfoSap1Page()
{
InitializeComponent();
#if __IOS__
UIDevice device = new UIDevice();
modelLabel.Text = device.Model.ToString();
versionLabel.Text = String.Format("{0} {1}", device.SystemName,
device.SystemVersion);

128
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API
#elif __ANDROID__
modelLabel.Text = String.Format("{0} {1}", Build.Manufacturer,
Build.Model);
versionLabel.Text = Build.VERSION.Release.ToString();

#elif WINDOWS_APP || WINDOWS_PHONE_APP || WINDOWS_UWP


EasClientDeviceInformation devInfo = new EasClientDeviceInformation();
modelLabel.Text = String.Format("{0} {1}", devInfo.SystemManufacturer,
devInfo.SystemProductName);
versionLabel.Text = devInfo.OperatingSystem;

#endif
}
}
}

A vantagem de fazer dessa maneira é que dá pra controlar o código para as três plataformas num
único lugar. Vamos ao resultado.

129
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API

130
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API
Agora vejamos como fica o código num projeto PCL. Primeiro é necessário criar uma interface no
projeto PCL que declara a assinatura dos métodos que deseja implementar nos projetos específicos
das plataformas. Segue o código da interface:

namespace DisplayPlatformInfo
{
public interface IPlatformInfo
{
string GetModel();
string GetVersion();
}
}

Agora cada projeto de plataforma precisa de uma classe que implemente IplatformInfo. Vejamos
como fica essa classe no iOS.

131
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API
using System;
using UIKit;
using Xamarin.Forms;
[assembly: Dependency(typeof(DisplayPlatformInfo.iOS.PlatformInfo))]
namespace DisplayPlatformInfo.iOS
{
public class PlatformInfo : IPlatformInfo
{
UIDevice device = new UIDevice();
public string GetModel()
{
return device.Model.ToString();
}
public string GetVersion()
{
return String.Format("{0} {1}", device.SystemName,
device.SystemVersion);
}
}
}

Veja que a classe implementa a interface que criamos e seus dois métodos.

132
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API
Segue a implementação para o Android.

using System;
using Android.OS;
using Xamarin.Forms;
[assembly: Dependency(typeof(DisplayPlatformInfo.Droid.PlatformInfo))]
namespace DisplayPlatformInfo.Droid
{
public class PlatformInfo : IPlatformInfo
{
public string GetModel()
{
return String.Format("{0} {1}", Build.Manufacturer,
Build.Model);
}
public string GetVersion()
{
return Build.VERSION.Release.ToString();
}
}
}

133
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API
Segue a implementação para o projeto UWP.

using System;
using Windows.Security.ExchangeActiveSyncProvisioning;
using Xamarin.Forms;
[assembly: Dependency(typeof(DisplayPlatformInfo.UWP.PlatformInfo))]
namespace DisplayPlatformInfo.UWP
{
public class PlatformInfo : IPlatformInfo
{
EasClientDeviceInformation devInfo = new EasClientDeviceInformation();
public string GetModel()
{
return String.Format("{0} {1}", devInfo.SystemManufacturer,
devInfo.SystemProductName);
}
public string GetVersion()
{
return devInfo.OperatingSystem;
}
}
}

134
#Dominando o Xamarin.Forms

Xamarin.Forms
Chamadas a API
Agora é só usar a classe DependencyService no projeto PCL para acessar os dados desejados.
Vamos usar o método Get, que retorna uma instância da classe específica da plataforma que
implementou a nossa interface IplatformInfo.

namespace DisplayPlatformInfo
{
public partial class DisplayPlatformInfoPage : ContentPage
{
public DisplayPlatformInfoPage()
{
InitializeComponent();
IPlatformInfo platformInfo = DependencyService.Get<IPlatformInfo>();
modelLabel.Text = platformInfo.GetModel();
versionLabel.Text = platformInfo.GetVersion();
}
}
}

Fácil e rápido nos dois tipos de projeto: SAP e PCL. Escolha o que for mais apropriado para o seu
projeto.

135
#Dominando o Xamarin.Forms

Xamarin.Forms
Markup Extensions
Markup Extensions (extensões de marcação) é uma técnica do XAML para obter um valor que nem
é um primitivo e nem um tipo XAML específico. As marcações são feitas utilizando chaves: “{” e
“}”. Quando se utiliza os serviços .NET do XAML, podemos utilizar algumas marcações pré-
definidas em System.Xaml. É possível ainda criar suas próprias marcações. Por fim, existe a
possibilidade de utilizar marcações definidas por um framework particular.

Várias marcações são implementadas pelo .NET. Essas marcações fazem parte da especificação
XAML. Elas são identificadas normalmente pelo prefixo “x:”. Vejamos alguns deles.

x:Type: fornece o objeto Type para determinado tipo nomeado.

x:Static: produz valores estáticos para entidades de código que não são exatamente do mesmo
valor da propriedade. As entidades de código podem ser: uma constante, uma propriedade
estática, um campo, o valor de uma enumeração.

x:Null: especifica o valor nulo para um membro do XAML. Dependendo do caso, null nem sempre é
o valor padrão de uma propriedade.

x:Array: suporte a criação de arrays na sintaxe XAML.

x:Reference: representa uma referência para outro objeto identificado por c:Name.

136
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
Uma das estruturas mais básicas no C# é a propriedade (property). Uma propriedade nada mais é
do que um campo (field) com get e set, ou seja, com métodos que tem a capacidade para
consultar ou modificar a propriedade. Tal definição de propriedade é conhecida como CLR property
porque é suportado pelo .NET. CLR significa Common Language Runtime. O Xamarin.Forms tem
uma definição melhorada para propriedades chamada de bindable property, encapsulada pela
classe BindableProperty e suportada pela classe BindableObject.

public class MyClass


{

double quality;
public double Quality
{
set
{
quality = value;
// Do something with the new value
}
get
{
return quality;
}
}

}

137
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
Uma das estruturas mais básicas no C# é a propriedade (property). Uma propriedade nada mais é
do que um campo (field) com get e set, ou seja, com métodos que tem a capacidade para
consultar ou modificar a propriedade. Tal definição de propriedade é conhecida como CLR property
porque é suportado pelo .NET. CLR significa Common Language Runtime. O Xamarin.Forms tem
uma definição melhorada para propriedades chamada de bindable property, encapsulada pela
classe BindableProperty e suportada pela classe BindableObject.

A classe BindableObject serve para realizar vinculações entre duas propriedades ou dois objetos
para que os mesmos tenham o mesmo valor, o chamado data binding. Mas essa classe também
suporta estilos e marcações do tipo DynamicResource.

Veja como setar valores diretamente no código.

public class PropertySettingsPage : ContentPage


{
public PropertySettingsPage()
{
Label label1 = new Label();
label1.Text = "Text with CLR properties";
label1.IsVisible = true;
label1.Opacity = 0.75;
label1.HorizontalTextAlignment = TextAlignment.Center;

138
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
label1.VerticalOptions = LayoutOptions.CenterAndExpand;
label1.TextColor = Color.Blue;
label1.BackgroundColor = Color.FromRgb(255, 128, 128);
label1.FontSize = Device.GetNamedSize(NamedSize.Medium, new Label());
label1.FontAttributes = FontAttributes.Bold | FontAttributes.Italic;
Label label2 = new Label();
label2.SetValue(Label.TextProperty, "Text with bindable properties");
label2.SetValue(Label.IsVisibleProperty, true);
label2.SetValue(Label.OpacityProperty, 0.75);
label2.SetValue(Label.HorizontalTextAlignmentProperty, TextAlignment.Center);
label2.SetValue(Label.VerticalOptionsProperty, LayoutOptions.CenterAndExpand);
label2.SetValue(Label.TextColorProperty, Color.Blue);
label2.SetValue(Label.BackgroundColorProperty, Color.FromRgb(255, 128, 128));
label2.SetValue(Label.FontSizeProperty,
Device.GetNamedSize(NamedSize.Medium, new Label()));
label2.SetValue(Label.FontAttributesProperty,
FontAttributes.Bold | FontAttributes.Italic);
Content = new StackLayout
{
Children =
{
label1,
label2
}
};
}
}
139
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
O método SetValue é definido por BindableObject. É interessante notar como é configurada a
propriedade Text neste caso:

label2.SetValue(Label.TextProperty, "Text with bindable properties");

TextProperty é um field estático, um objeto do tipo BindableProperty que pode ser modificado pelo
método SetValue. Se observar a documentação de Label, verá que ele contém 10 propriedades.
Existem 10 fields do tipo BindableProperty equivalentes.

140
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
Por trás das cortinas, uma vinculação (data binding) instala manipuladores eventos (event
handlers) e manipula os valores de uma propriedade para outra. O data binding é uma “mão na
roda” e ajuda muito no desenvolvimento.

Várias propriedades, métodos e classes estão envolvidos no data binding:


A classe Binding (que deriva de BindingBase) define muitas características de uma vinculação.

A propriedade BindingContext é definida pela classe BindableObject.

O método SetBinding também é definido pela classe BindableObject.

A classe BindableObjectExtensions define duas implementações a mais para SetBinding.

Duas classes suportam extensões de marcação do XAML para vinculações:


A classe BindingExtension class, que é privada para o Xamarin.Forms, fornece suporte para a
extensão de marcação Binding que é utilizada para definir as vinculações no XAML.

A classe ReferenceExtension que é crucial para vinculações.

Duas interfaces estão envolvidas no data binding:


INotifyPropertyChanged é a interface padrão utilizada pelas classes para notificar outras que
houve uma alteração numa propriedade.

IvalueConverter: usada para definir classes que convertem valores de um tipo para outro.

141
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
O conceito mais fundamental das vinculações (data bindings) é o seguinte: data bindings sempre
tem uma origem (source) e um destino (target). A origem é a propriedade de um objeto,
normalmente uma que muda dinamicamente em tempo de execução. Quando essa propriedade
muda, o data binding automaticamente atualiza o destino, que é uma propriedade de outro objeto.

O destino de um binding precisa ser suportado por um objeto BindableProperty. A origem precisa
implementar algum mecanismo de notificação para avisar ao destino que houve uma alteração.
Esse mecanismo de notificação é a interface InotifyPropertyChanged, que contém apenas um
método chamado PropertyChanged, que uma classe dispara quando uma propriedade é alterada.

A classe BindableObject implementa InotifyPropertyChanged. Nesse caso, aquelas propriedades


vinculadas a BindlableObject serão atualizadas automaticamente!

Como configurar um data binding diretamente no código? No código a seguir temos um Label e um
Slider. Criaremos a vinculação entre as propriedades Opacity do Label e Value do Slider. Vejamos.

142
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
public class OpacityBindingCodePage : ContentPage
{
public OpacityBindingCodePage()
{
Label label = new Label
{
Text = "Opacity Binding Demo",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.Center
};
Slider slider = new Slider
{
VerticalOptions = LayoutOptions.CenterAndExpand
};
// Set the binding context: target is Label; source is Slider.
label.BindingContext = slider;
// Bind the properties: target is Opacity; source is Value.
label.SetBinding(Label.OpacityProperty, "Value");
// Construct the page.
Padding = new Thickness(10, 0);
Content = new StackLayout
{
Children = { label, slider }
};
}
}
143
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações

144
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
Para realizar a mesma tarefa no XAML, é preciso utilizar duas extensões de marcação:


x:Reference, que é parte da especificação XAML 2009.

Binding, que é parte da interface do usuário XAML da Microsoft.

A marcação Binding é a mais extensa e complexa do Xamarin.Forms. Para realizar o binding no


XAML, o caminho é o seguinte:


Configurar a propriedade BindingContext do elemento destino (o Label) para uma marcação
x:Reference que faz referência ao elemento destino (o Slider).

Configurar a propriedade de destino (a propriedade Opacity do Label) para uma marcação
Binding que referencia a propriedade de destino (a propriedade Value do Slider).

Veja a seguir como fica o código XAML.

145
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="OpacityBindingXaml.OpacityBindingXamlPage"
Padding="10, 0">
<StackLayout>
<Label Text="Opacity Binding Demo"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
BindingContext="{x:Reference Name=slider}"
Opacity="{Binding Path=Value}" />
<Slider x:Name="slider"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

Com essa definição no XAML não é preciso fazer nada no código C#. O BindingContext é uma de
duas maneiras de vincular os objetos origem e destino. Você pode dispensar o BindingContext e
usar a propriedade Source da classe Binding ou da extensão de marcação Binding. Se você
especificar os dois, o Source terá precedência em relação ao BindingContext. Veja a seguir como
usar o Source.

146
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
Veja abaixo outra maneira de trabalhar no XAML. Dessa vez temos uma extensão de marcação com
dois argumentos, sendo que um deles é outra extensão de marcação.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BindingSourceXaml.BindingSourceXamlPage"
Padding="10, 0">
<StackLayout>
<Label Text="Binding Source Demo"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
Opacity="{Binding Source={x:Reference Name=slider},
Path=Value}" />
<Slider x:Name="slider"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

147
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
Podemos utilizar x:Reference como um elemento. Observe:

<Label Text="Binding Source Demo"


FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center">
<Label.Opacity>
<Binding Path="Value">
<Binding.Source>
<x:Reference Name="slider" />
</Binding.Source>
</Binding>
</Label.Opacity>
</Label>

Você vai observar que em alguns casos é melhor usar o BindingContext e que em outros ele não
poderá ser utilizado, restando a utilização do Source. Talvez a principal diferença entre
BindingContext e Source seja uma característica do primeiro que o faz diferente de qualquer outra
propriedade do Xamarin.Forms: o BindingContext se propaga pela árvore visual, ou seja, se você
configurar o BindingContext num StackLayout, ele aplica a todos os filhos desse StackLayout e aos
filhos desses filhos até o final da árvore. Vamos a um exemplo para ficar mais claro!

148
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
Digamos que você queira criar uma aplicação que permita que o usuário navegue pela internet.
Para isso, você utilizará um WebView. O WebView é com um browser, um navegador. Ele possui
dois métodos que implementam os botões Back e Forward, encontrados nos navegadores. Os
métodos são: GoBack e GoForward.

Nós podemos inserir dois botões na tela com essa finalidade, sendo que, em determinados
momentos um dos botões ou os dois deverão estar desabilitados, pois ainda não existe pra onde
navegar. Esse controle de habilitação/desabilitação dos botões será feito com vinculações
diretamente no XAML. Isso será possível porque o WebView define duas propriedades booleanas
chamadas CanGoBack e CanGoForward.

Então faremos o seguinte: colocaremos um StackLayout para armazenar os botões e já definiremos


o BindingContext do StackLayout apontando para o WebView. Nesse momento todos os filhos de
StackLayout herdarão essa vinculação. Daí, nos botões, bastará que apontemos a propriedade
IsEnabled para os métodos CanGoBack e CanGoForward. Simples assim!

Veja como fica o código XAML.

149
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebViewDemo.WebViewDemoPage">
<StackLayout>
<Entry Keyboard="Url"
Placeholder="web address"
Completed="OnEntryCompleted" />
<StackLayout Orientation="Horizontal"
BindingContext="{x:Reference webView}">
<Button Text="&#x21D0;"
FontSize="Large"
HorizontalOptions="FillAndExpand"
IsEnabled="{Binding CanGoBack}"
Clicked="OnGoBackClicked" />
<Button Text="&#x21D2;"
FontSize="Large"
HorizontalOptions="FillAndExpand"
IsEnabled="{Binding CanGoForward}"
Clicked="OnGoForwardClicked" />
</StackLayout>
<WebView x:Name="webView"
VerticalOptions="FillAndExpand"
Source="https://xamarin.com" />
</StackLayout>
</ContentPage>

150
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
Observe que os botões tem o evento Clicked. Vejamos como fica a implementação desses métodos
no código C#.

public partial class WebViewDemoPage : ContentPage


{
public WebViewDemoPage()
{
InitializeComponent();
}
void OnEntryCompleted(object sender, EventArgs args)
{
webView.Source = ((Entry)sender).Text;
}
void OnGoBackClicked(object sender, EventArgs args)
{
webView.GoBack();
}
void OnGoForwardClicked(object sender, EventArgs args)
{
webView.GoForward();
}
}

E aí está. Simples não! Veja o resultado na página seguinte.

151
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações

152
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
Observe o código a seguir:

<Label FontSize="{Binding Source={x:Reference slider}, Path=Value}" />


<Slider x:Name="slider" Maximum="100" />

---------

<Label x:Name="label" />


<Slider Maximum="100" Value="{Binding Source={x:Reference label}, Path=FontSize}" />

No primeiro temos um Label cuja propriedade FontSize aponta para o Value de um Slider. No
segundo temos um Slider cuja propriedade Value aponta para o FontSize do Label. Humm, esse
segundo parece não fazer muito sentido! Como vamos alterar o tamanho da fonte de tal maneira
que isso reflita no valor do Slider? Pois é, mas irá funciona da mesma maneira que o primeiro:
alterando o valor do Slider veremos o efeito no tamanho da fonte! Isso ocorre por causa de uma
“mágica” chamada “binding mode”.

A relação entre origem (source) e destino (target) será definida pela enumeração BindingMode,
que tem os seguintes membros:

153
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações

Default — ao ser escolhido, aponta para OneWay.

OneWay — alterações na fonte afetam o destino (normal).

OneWayToSource — alterações no destino afetam a fonte.

TwoWay — alterações na fonte e no destino afetam ambos.

O funcionamento é o seguinte:

Se você não especificar nada, o modo padrão é o OneWay para propriedades que pode ser lidas e
escritas e OneWayToSource para propriedades somente-leitura. É possível sobrescrever o modo
padrão definindo a propriedade Mode do Binding.

A maioria das propriedades funcionam em OneWay. Mas existem algumas que funcionam por
padrão no modo TwoWay. Observe a tabela. A maioria dessas propriedades que tem o valor padrão
TwoWay são utilizadas em cenários MVVM com objetos de dados como source e views como target.

154
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
A classe Binding possui uma propriedade StringFormat que permite a formatação da string que
será apresentada. Segue o mesmo padrão do .NET. A formatação desejada ficará entre chaves. Por
exemplo: “{0:F3}” vai apresentar um double com três casas decimais.

No exemplo a seguir podemos ver a exibição de quatro views: Slider, Entry, Stepper e Switch, cada
um deles será formatado. Observe atentamente.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ShowViewValues.ShowViewValuesPage"
Padding="10, 0">
<StackLayout>
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='The Slider value is {0:F3}'}" />
<Slider x:Name="slider" />
</StackLayout>
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="{Binding Source={x:Reference entry},
Path=Text,
StringFormat='The Entry text is &#x201C;{0}&#x201D;'}" />
<Entry x:Name="entry" />
</StackLayout>

155
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="{Binding Source={x:Reference stepper},
Path=Value,
StringFormat='The Stepper value is {0}'}" />
<Stepper x:Name="stepper" />
</StackLayout>
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="{Binding Source={x:Reference switch},
Path=IsToggled,
StringFormat='The Switch value is {0}'}" />
<Switch x:Name="switch" />
</StackLayout>
</StackLayout>
</ContentPage>

Agora observe o resultado na página seguinte.

156
#Dominando o Xamarin.Forms

Xamarin.Forms
Vinculações

157
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
As aplicações Xamarin.Forms contém múltiplos elementos com configurações de propriedades
idênticas. Por exemplo, você pode ter vários botões com a mesma fonte, mesmas cores e mesmas
opções de layout.

Para configurar um estilo padrão para vários elementos é preciso utilizar a classe Style, que é uma
coleção de configurações de propriedades em um objeto. É possível setar o objeto Style para a
propriedade Style de qualquer classe que deriva de VisualElement. Geralmente você vai aplicar o
mesmo objeto Style para múltiplos elementos e o estilo é compartilhado entre esses elementos.

Os estilos ajudam a diminuir código no arquivo XAML e ajudam na manutenção, pois o código
poderá ser mais facilmente modificado.

Observe no código a seguir alguns botões que possuem as mesmas características. A única
diferença é a propriedade Text. Veja como o código fica grande e repetitivo se feito dessa forma.

158
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
<StackLayout>
<Button Text=" Carpe diem "
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
TextColor="Red"
FontSize="Large">
<Button.BackgroundColor>
<OnPlatform x:TypeArguments="Color"
Android="#404040" />
</Button.BackgroundColor>
<Button.BorderColor>
<OnPlatform x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
</Button.BorderColor>
</Button>
<Button Text=" Sapere aude "
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
TextColor="Red"
FontSize="Large">
<Button.BackgroundColor>
<OnPlatform x:TypeArguments="Color"
Android="#404040" />

159
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
</Button.BackgroundColor>
<Button.BorderColor>
<OnPlatform x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
</Button.BorderColor>
</Button>
<Button Text=" Discere faciendo "
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BorderWidth="3"
TextColor="Red"
FontSize="Large">
<Button.BackgroundColor>
<OnPlatform x:TypeArguments="Color"
Android="#404040" />
</Button.BackgroundColor>
<Button.BorderColor>
<OnPlatform x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
</Button.BorderColor>
</Button>
</StackLayout>

160
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
Agora imagine o código da seguinte forma:

<StackLayout>
<Button Text=" Carpe diem "
Style="{StaticResource buttonStyle}" />
<Button Text=" Sapere aude "
Style="{StaticResource buttonStyle}" />
<Button Text=" Discere faciendo "
Style="{StaticResource buttonStyle}" />
</StackLayout>

Bem melhor né? Mas onde está definido esse “buttonStyle”? Nós precisamos criar um
ResourceDictionary. Podemos fazer isso no início da página. Dentro desse ResourceDictionary nós
colocaremos uma tag Style com um x:Key que é o identificador do estilo. Advinha o nome dessa
nosa x:Key? Se você pensou em “buttonStyle” acertou! Também é preciso definir o alvo desse
estilo através da propriedade TargetType. Veja uma parcial do código com o que já comentamos.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BasicStyle.BasicStylePage">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">

</Style>
</ResourceDictionary>
</ContentPage.Resources> 161
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
O Style contém uma propriedade muito importante chamada Setter. Cada Setter é responsável por
definir a característica de uma propriedade do estilo. A classe Setter possui duas propriedades:


Property do tipo BindableProperty.

Value do tipo Object.

Observe mais uma parcial do código.

<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BorderWidth" Value="3" />
<Setter Property="TextColor" Value="Red" />
<Setter Property="FontSize" Value="Large" />

</Style>
</ResourceDictionary>
</ContentPage.Resources>

E se for preciso fazer algum tipo de controle por plataforma? Não tem problema, você também usa
o Setter em conjunto com OnPlatform. Veja como fica no código seguinte.

162
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
<Setter Property="BackgroundColor">
<Setter.Value>
<OnPlatform x:TypeArguments="Color"
Android="#404040" />
</Setter.Value>
</Setter>
<Setter Property="BorderColor">
<Setter.Value>
<OnPlatform x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
</Setter.Value>
</Setter>

Agora vejamos o código completo para que você o estude e compreenda como é fácil utilizar estilos
e melhorar muito o código.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BasicStyle.BasicStylePage">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BorderWidth" Value="3" />
<Setter Property="TextColor" Value="Red" />
163
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
<Setter Property="FontSize" Value="Large" />
<Setter Property="BackgroundColor">
<Setter.Value>
<OnPlatform x:TypeArguments="Color"
Android="#404040" />
</Setter.Value>
</Setter>
<Setter Property="BorderColor">
<Setter.Value>
<OnPlatform x:TypeArguments="Color"
Android="White"
WinPhone="Black" />
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Button Text=" Carpe diem "
Style="{StaticResource buttonStyle}" />
<Button Text=" Sapere aude "
Style="{StaticResource buttonStyle}" />
<Button Text=" Discere faciendo "
Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage>

164
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)

165
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
Interessante né? E se você quisesse definir um estilo único para todas os elementos? Neste caso,
você precisa de um estilo para as propriedades definidas pela classe View. Veja como fica o código
e como utilizamos o estilo para Buttons e Labels.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BasicStyle.BasicStylePage">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="viewStyle" TargetType="View">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BackgroundColor" Value="Pink" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Button Text=" Carpe diem "
Style="{StaticResource viewStyle}" />
<Label Text ="A bit of text"
Style="{StaticResource viewStyle}" />
<Button Text=" Sapere aude "
Style="{StaticResource viewStyle}" />
<Label Text ="Another bit of text"
Style="{StaticResource viewStyle}" />
<Button Text=" Discere faciendo "
Style="{StaticResource viewStyle}" />
</StackLayout> 166
</ContentPage>
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)

167
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
Saiba que um estilo pode derivar de outro. Para que isso seja possível utilizamos a propriedade
BasedOn. Estude o código seguinte atentamente. Ele possui quatro estilos: o primeiro é o
“visualStyle”. Daí temos o “baseStyle” que deriva de “visualStyle”. Finalmente temos os estilos
“labelStyle” and “buttonStyle” que derivam de “baseStyle”.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit=
"clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
x:Class="StyleInheritance.StyleInheritancePage">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="visualStyle" TargetType="VisualElement">
<Setter Property="BackgroundColor"
Value="{toolkit:HslColor H=0, S=1, L=0.8}" />
</Style>
<Style x:Key="baseStyle" TargetType="View"
BasedOn="{StaticResource visualStyle}">
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
</Style>
<Style x:Key="labelStyle" TargetType="toolkit:AltLabel"
BasedOn="{StaticResource baseStyle}">
<Setter Property="TextColor" Value="Black" />
<Setter Property="PointSize" Value="12" />
</Style>
168
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)
<Style x:Key="buttonStyle" TargetType="Button"
BasedOn="{StaticResource baseStyle}">
<Setter Property="TextColor" Value="Blue" />
<Setter Property="FontSize" Value="Large" />
<Setter Property="BorderColor" Value="Blue" />
<Setter Property="BorderWidth" Value="2" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Style>
<StaticResourceExtension Key="visualStyle" />
</ContentPage.Style>
<StackLayout>
<Button Text=" Carpe diem "
Style="{StaticResource buttonStyle}" />
<toolkit:AltLabel Text ="A bit of text"
Style="{StaticResource labelStyle}" />
<Button Text=" Sapere aude "
Style="{StaticResource buttonStyle}" />
<toolkit:AltLabel Text ="Another bit of text"
Style="{StaticResource labelStyle}" />
<Button Text=" Discere faciendo "
Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage>

169
#Dominando o Xamarin.Forms

Xamarin.Forms
Estilos (styles)

170
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Uma parte muito importante de uma aplicação é a utilização de imagens. Para utilizar imagens com o
Xamarin.Forms utilizamos uma view chamada Image. Você pode utilizar os seguintes formatos sem problemas:
JPEG, PNG, GIF e BMP.

Image possui uma propriedade Source que você configura para o objeto do tipo ImageSource. As imagens
podem vir de várias origens (sources), por isso a classe ImageSource define quatro métodos estáticos de criação
que retornam um objeto ImageSource:


ImageSource.FromUri para acessar uma imagem na web.

ImageSource.FromResource para acessar uma imagem armazenada com um recurso embutido num PCL.

ImageSource.FromFile para acessar uma imagem armazenada como conteúdo de um projeto específico de
uma plataforma.

ImageSource.FromStream para carregar uma imagem usando o objeto Stream do .NET.

Geralmente utilizamos os métodos ImageSource.FromUri e ImageSource.FromResource para obter


imagens independentes da plataforma e ImageSource.FromFile para carregar imagens que
dependem da plataforma.

Para carregar uma imagem no código C# é muito simples. Observe a seguir.

171
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
public class WebBitmapCodePage : ContentPage
{
public WebBitmapCodePage()
{
string uri = "https://developer.xamarin.com/demo/IMG_1415.JPG";
Content = new Image
{
Source = ImageSource.FromUri(new Uri(uri))
};
}
}

Caso não exista uma imagem no endereço solicitado, não ocorrerá nenhuma exceção. Existe uma
maneira de simplificar esse método. Observe.

public class WebBitmapCodePage : ContentPage


{
public WebBitmapCodePage()
{
Content = new Image
{
Source = "https://developer.xamarin.com/demo/IMG_1415.JPG"
};
}
}

172
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens

173
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Para carregar a imagem diretamente no XAML faríamos da seguinte forma:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebBitmapXaml.WebBitmapXamlPage">

<Image Source="https://developer.xamarin.com/demo/IMG_3256.JPG" />

</ContentPage>

Outra forma de fazer é instanciar explicitamente um objeto UriImageSource e definir a propriedade


URI. Veja:

<Image>
<Image.Source>
<UriImageSource Uri="https://developer.xamarin.com/demo/IMG_3256.JPG" />
</Image.Source>
</Image>

174
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens

175
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
O objeto Image ocupa toda a área retangular da página. Tal objeto possui uma propriedade
chamada Aspect que controla como a imagem será renderizada dentro do seu retângulo. São três
as opções:


AspectFit — o padrão. A imagem se encaixa nos limites do seu retângulo, sem prejudicar sua
proporção.

Fill — aplica um stretch, ou seja, estica a imagem sem preservar sua proporção (aspect ratio)

AspectFill — preserva a proporção (aspect ratio), mas corta a imagem

É muito fácil alterar isso no código:

<Image Source="https://developer.xamarin.com/demo/IMG_3256.JPG"
Aspect="Fill" />

Veja o resultado na página seguinte.

176
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens

177
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
E como ficaria o AspectFill?

<Image Source="https://developer.xamarin.com/demo/IMG_3256.JPG"
Aspect="AspectFill" />

178
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Na maioria dos casos você vai acessar uma imagem que está embutida no projeto (embedded
resource). Você deve adicionar as imagens no projeto PCL e configurar o Build Action da imagem
para EmbeddedResource. É crucial que faça isso!

Para carregar uma imagem embutida diretamente no código C# proceda da seguinte forma:

public class ResourceBitmapCodePage : ContentPage


{
public ResourceBitmapCodePage()
{
Content = new Image
{
Source = ImageSource.FromResource(
"ResourceBitmapCode.Images.ModernUserInterface256.jpg"),
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};
}
}

Veja que estamos centralizando a imagem. Dessa forma, a mesma não será esticada para toda a
página. Observe o resultado a seguir.

179
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens

180
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
E para carregar uma imagem embutida diretamente no XAML? Infelizmente não existe uma classe
ResourceImageSource. Será preciso criar uma extensão de marcação (markup extension). Segue
um exemplo:

namespace StackedBitmap
{
[ContentProperty("Source")]
public class ImageResourceExtension : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Source == null)
return null;
return ImageSource.FromResource(Source);
}
}
}

ImageResourceExtension possui uma propriedade chamada Source para que seja definido o ID do
recurso. O método ProvideValue simplesmente chama ImageSource.FromResource com a
propriedade Source como parâmetro. Definida a extensão, a mesma poderá ser utilizada no XAML.
Lembrando que essa classe deve fazer parte do mesmo assembly que contém o recurso embutido,
geralmente o projeto PCL.

181
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Observe que a propriedade Source do Image está apontando para a extensão que criamos
anteriormente.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:StackedBitmap "
x:Class="StackedBitmap.StackedBitmapPage">
<StackLayout>
<Label Text="320 x 240 Pixel Bitmap"
FontSize="Medium"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"
BackgroundColor="Aqua"
SizeChanged="OnImageSizeChanged" />
<Label x:Name="label"
FontSize="Medium"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>

Vamos inserir um código C# para saber a altura e largura da imagem.

182
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Observe que a propriedade Source do Image está apontando para a extensão que criamos
anteriormente.

public partial class StackedBitmapPage : ContentPage


{
public StackedBitmapPage()
{
InitializeComponent();
}
void OnImageSizeChanged(object sender, EventArgs args)
{
Image image = (Image)sender;
label.Text = String.Format("Render size = {0:F0} x {1:F0}",
image.Width, image.Height);
}
}

A imagem vai se comportar de forma diferente, dependendo da plataforma. Veja o que ocorre na
página seguinte.

183
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens

184
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Se preferir que o tamanho da imagem seja o mesmo renderizado por cada plataforma, configure a
propriedade HorizontalOptions para um valor diferente de Fill. Vamos colocar Center e observar o
resultado.

<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"


HorizontalOptions="Center"
BackgroundColor="Aqua"
SizeChanged="OnImageSizeChanged" />

185
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
E se você quiser definir o tamanho da imagem de acordo com o que desejar? Isso é possível
através das propriedades WidthRequest (largura) HeightRequest (altura).

É importante frisar que não é possível utilizar o WidthRequest para aumentar o tamanho da
imagem. Se a largura da imagem é 100 e você colocar o valor 200 no WidthRequest, a imagem
ficará com o tamanho máximo padrão, que o no caso é 100.

Se você souber o tamanho da imagem, é bom setar diretamente esse tamanho no código:

<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"


WidthRequest="320"
HeightRequest="240"
HorizontalOptions="Center"
BackgroundColor="Aqua"
SizeChanged="OnImageSizeChanged" />

Note, porém, que a imagem pode ficar com uma resolução ruim, pois cada plataforma tem uma
estratégia diferente para renderizá-la. De repente é melhor você usar uma imagem maior, com
mais resolução, e então restringir o seu tamanho. Por exemplo, digamos que você quer exibir uma
imagem de 320x240. Se você dividir 240 por 320 chegará a 75%. Ou seja, a altura dessa imagem
equivale a 75% da sua largura. Dessa forma, você poderá usar uma imagem de 1000x750 e
restringir o seu tamanho diretamente no código XAML como vimos acima para melhorar a
resolução final.

186
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Vamos a um exemplo onde teremos um visualizador de imagens. As imagens serão carregadas a
partir de um arquivo JSON disponível na web. O arquivo pode ser visto no link a seguir:

https://developer.xamarin.com/demo/stock.json

Veja parte do conteúdo, que traz uma lista de imagens:

{
"photos": [
"https://developer.xamarin.com/demo/IMG_0074.JPG",
"https://developer.xamarin.com/demo/IMG_0078.JPG",
"https://developer.xamarin.com/demo/IMG_0308.JPG",
"https://developer.xamarin.com/demo/IMG_0437.JPG",
"https://developer.xamarin.com/demo/IMG_0462.JPG",
"https://developer.xamarin.com/demo/IMG_0475.JPG",
"https://developer.xamarin.com/demo/IMG_0563.JPG",
"https://developer.xamarin.com/demo/IMG_0565.JPG",
"https://developer.xamarin.com/demo/IMG_0580.JPG",
"https://developer.xamarin.com/demo/IMG_0613.JPG",
"https://developer.xamarin.com/demo/IMG_0718.JPG",
"https://developer.xamarin.com/demo/IMG_0722.JPG",
"https://developer.xamarin.com/demo/IMG_0866.JPG",
"https://developer.xamarin.com/demo/IMG_0925.JPG",
"https://developer.xamarin.com/demo/IMG_1010.JPG",

187
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Primeiro analisemos o código XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ImageBrowser.ImageBrowserPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<StackLayout>
<Image x:Name="image"
VerticalOptions="CenterAndExpand"
PropertyChanged="OnImagePropertyChanged" />
<Label x:Name="filenameLabel"
HorizontalOptions="Center" />
<ActivityIndicator x:Name="activityIndicator" />
<StackLayout Orientation="Horizontal">
<Button x:Name="prevButton"
Text="Previous"
IsEnabled="false"
HorizontalOptions="CenterAndExpand"
Clicked="OnPreviousButtonClicked" />
<Button x:Name="nextButton"
Text="Next"
IsEnabled="false"
HorizontalOptions="CenterAndExpand"
Clicked="OnNextButtonClicked" />
</StackLayout> 188
</StackLayout>
</ContentPage>
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Temos dois botões para navegação que invocam dois métodos: OnPreviousButtonClicked e
OnNextButtonClicked. O Image contém um manipulador PropertyChanged que é implementado
pelo BindableObject e é disparado quando uma propriedade vinculável (bindable) modifica o seu
valor. Apontamos PropertyChanged para o método OnImagePropertyChanged.

Também usamos nessa aplicação um ActivityIndicator, que mostra alguma informação sobre o
progresso da operação. Muito utilizado em operações que possam demorar, para que o usuário
saiba que existe algo em processamento.

O ActivityIndicator possui uma propriedade booleana chamada IsRunning. Normalmente essa


propriedade é “false” e o ActivityIndicator é invisível. Se essa propriedade for alterada para “true” o
ActivityIndicator ficará visível. As três plataformas implementam um componente visual para
indicar que o programa está trabalhando. Cada plataforma apresentará algo diferente. No iOS é
uma roda giratória, no Android um círculo parcial girando e no Windows uns pontinhos se movendo
na tela.

Vamos analisar agora o código C# que mostra como recuperar o arquivo JSON, como lidar com
cada elemento do arquivo e como os eventos dos botões são implementados para que as imagens
sejam exibidas para o usuário.

189
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
public partial class ImageBrowserPage : ContentPage
{
[DataContract]
class ImageList
{
[DataMember(Name = "photos")]
public List<string> Photos = null;
}
WebRequest request;
ImageList imageList;
int imageListIndex = 0;
public ImageBrowserPage()
{
InitializeComponent();
// Get list of stock photos.
Uri uri = new Uri("https://developer.xamarin.com/demo/stock.json");
request = WebRequest.Create(uri);
request.BeginGetResponse(WebRequestCallback, null);
}
void WebRequestCallback(IAsyncResult result)
{
Device.BeginInvokeOnMainThread(() =>
{
try
{

190
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Stream stream = request.EndGetResponse(result).GetResponseStream();
// Deserialize the JSON into imageList;
var jsonSerializer = new DataContractJsonSerializer(typeof(ImageList));
imageList = (ImageList)jsonSerializer.ReadObject(stream);
if (imageList.Photos.Count > 0)
FetchPhoto();
}
catch (Exception exc)
{
filenameLabel.Text = exc.Message;
}
});
}
void OnPreviousButtonClicked(object sender, EventArgs args)
{
imageListIndex--;
FetchPhoto();
}
void OnNextButtonClicked(object sender, EventArgs args)
{
imageListIndex++;
FetchPhoto();
}

191
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
void FetchPhoto()
{
// Prepare for new image.
image.Source = null;
string url = imageList.Photos[imageListIndex];
// Set the filename.
filenameLabel.Text = url.Substring(url.LastIndexOf('/') + 1);
// Create the UriImageSource.
UriImageSource imageSource = new UriImageSource
{
Uri = new Uri(url + "?Width=1080"),
CacheValidity = TimeSpan.FromDays(30)
};
// Set the Image source.
image.Source = imageSource;
// Enable or disable buttons.
prevButton.IsEnabled = imageListIndex > 0;
nextButton.IsEnabled = imageListIndex < imageList.Photos.Count - 1;
}
void OnImagePropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (args.PropertyName == "IsLoading")
{
activityIndicator.IsRunning = ((Image)sender).IsLoading;
}
}
}
192
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
WebRequest realiza o download do arquivo JSON. Isso é feito numa thread separada para não
travar a aplicação. Sempre que o usuário clicar num dos botões, o método FetchPhoto será
chamado para que seja feito o download de uma nova imagem com base no caminho do elemento
do arquivo JSON.

A classe Image possui uma propriedade booleana chamada IsLoading que aponta para a
propriedade vinculável IsLoadingProperty. Ou seja, quando IsLoading sofre alguma alteração, o
evento PropertyChanged é disparado. O sistema usa o manipulador do PropertyChanged (o método
OnImagePropertyChanged) para definir a propriedade IsRunning do ActivityIndicator para o mesmo
valor do IsLoading do Image.

Veja o resultado na página seguinte.

193
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens

194
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Também é possível acessar as imagens locais e remotas através do ImageSource.FromStream da
classe StreamImageSource.

O argumento que deve ser passado para o método ImageSource.FromStream é um objeto Func, ou
seja, um método sem argumentos! Esse método é que vai retornar um objeto Stream.

Primeiro vejamos o código XAML.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BitmapStreams.BitmapStreamsPage">
<StackLayout>
<Image x:Name="image1"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Image x:Name="image2"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>

A primeira imagem será definida como um recurso embutido do projeto PCL. A segunda será
acessada remotamente num endereço web.

195
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Para acessar uma imagem como recurso embutido diretamente no código C# proceda da seguinte
forma:

public partial class BitmapStreamsPage : ContentPage


{
public BitmapStreamsPage()
{
InitializeComponent();
// Load embedded resource bitmap.
string resourceID = "BitmapStreams.Images.IMG_0722_512.jpg";
image1.Source = ImageSource.FromStream(() =>
{
Assembly assembly = GetType().GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream(resourceID);
return stream;
});

}
}

O argumento ImageSource.FromStream é definido como uma função que retorna um objeto


Stream. Assim sendo, tal argumento é utilizado aqui como uma função lambda. Se por um acaso o
comando GetManifestResourceStream não funcionar, certifique-se de ter marcado o Build Action da
imagem para EmbeddedResource.

196
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens

197
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
É possível também carregar imagens que estão armazenadas como recursos de um projeto
particular para determinada plataforma. As ferramentas para essa tarefa são: O método estático
ImageSource.FromFile e a classe correspondente FileImageSource. Provavelmente essa facilidade
será utilizada para carregar imagens em elementos de interface para o usuário.

Exemplos:


A propriedade Icon de MenuItem e ToolBarItem é do tipo FileImageSource.

A propriedade Image do Button tabém é do tipo FileImageSource.

Muitas vezes é melhor armazenar tais imagens por projeto, em cada plataforma, pois cada
plataforma permite armazenar imagens em várias resoluções diferentes e seleciona a melhor
dependendo do dispositivo. Essa é uma vantagem que só será aproveitada se as imagens forem
armazenadas por plataforma e se você usar ImageSource.FromFile e FileImageSource.

No projeto iOS, tais imagens serão encontradas na pasta Resources. Em projetos Android, você
encontrará algumas pastas na pasta Resources. Em projetos Windows, você encontrará as imagens
na pasta Assets e suas subpastas.

Observe no código a seguir como carregar uma imagem de acordo com a plataforma e que está
armazenada dentro do projeto de cada plataforma.

198
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
public class PlatformBitmapsPage : ContentPage
{
public PlatformBitmapsPage()
{
Image image = new Image
{
Source = new FileImageSource
{
File = Device.OnPlatform(iOS: "Icon-Small-40.png",
Android: "icon.png",
WinPhone: "Assets/StoreLogo.png")
},
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
Label label = new Label
{
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
image.SizeChanged += (sender, args) =>
{
label.Text = String.Format("Rendered size = {0} x {1}",
image.Width, image.Height);
};

199
#Dominando o Xamarin.Forms

Xamarin.Forms
Imagens
Content = new StackLayout
{
Children =
{
image,
label
}
};
}
}

200