Professional Documents
Culture Documents
Forms
1
#Dominando o Xamarin.Forms
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.
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?
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.
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.
●
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.
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:
●
No iOS, esse componente é uma “view”
chamada UISwitch.
●
No Android é um “widget” chamado Switch.
●
No Windows é um “control” chamado
ToggleSwitch.
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#.
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.
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:
●
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”.
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:
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.
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).
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).
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.
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.
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.
●
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.
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());
}
}
}
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.
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.
●
Start
●
Center
●
End
●
Fill
●
StartAndExpand
●
CenterAndExpand
●
EndAndExpand
●
FillAndExpand
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();
}
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."
};
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:
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.
●
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:
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
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
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:
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.
De:
Para:
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.
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.
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.
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á.
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.
76
#Dominando o Xamarin.Forms
Xamarin.Forms
Lidando com Tamanhos
O código a seguir exibe o tamanho da tela do dispositivo:
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):
É 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")
});
}
}
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
À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
}
}
};
}
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.
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:
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.
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.
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.
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:
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.
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.
<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#:
Veja que a assinatura contém uma palavra “partial” que indica que ela é apenas parte da definição
da classe Page1.
105
#Dominando o Xamarin.Forms
Xamarin.Forms
XAML
Vejamos agora o código XAML.
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>
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>
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="⇦"
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>
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 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.
127
#Dominando o Xamarin.Forms
Xamarin.Forms
Chamadas a API
using System;
using Xamarin.Forms;
#if __IOS__
using UIKit;
#elif __ANDROID__
using Android.OS;
#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();
#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: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: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.
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.
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:
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.
●
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.
●
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.
●
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.
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.
●
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).
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:
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.
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="⇐"
FontSize="Large"
HorizontalOptions="FillAndExpand"
IsEnabled="{Binding CanGoBack}"
Clicked="OnGoBackClicked" />
<Button Text="⇒"
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#.
151
#Dominando o Xamarin.Forms
Xamarin.Forms
Vinculações
152
#Dominando o Xamarin.Forms
Xamarin.Forms
Vinculações
Observe o código a seguir:
---------
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 “{0}”'}" />
<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>
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.
<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.
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.
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">
</ContentPage>
<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
<Image Source="https://developer.xamarin.com/demo/IMG_3256.JPG"
Aspect="Fill" />
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:
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>
182
#Dominando o Xamarin.Forms
Xamarin.Forms
Imagens
Observe que a propriedade Source do Image está apontando para a extensão que criamos
anteriormente.
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.
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:
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
{
"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.
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.
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.
<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:
}
}
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