Universal Windows Apps — parte 2

NetCoders
netcoders
Published in
10 min readJun 14, 2015
Universal App - 1 plataforma

Olá! Que bom que você voltou para continuarmos a conversa sobre desenvolver um único aplicativo e rodá-lo em qualquer dispositivo com Windows 10. Agora que você já instalou o Windows 10 e o Visual Studio 2015 RC, nós… espere. Como assim você ainda não fez isso? Vá lá no primeiro artigo, baixe e instale. Eu espero. Meu Slayer nível 65 no Tera Rising está mesmo precisando fazer umas quests pendentes…

Opa, você voltou! Agora que está tudo pronto, um último aviso: nessa parte estou supondo que você conheça XAML. Perae, você é da turma do Windows Form ou HTML? Meus pêsames, a festa não foi planejada para você, mas mesmo assim te convido a continuar lendo. Conhecimento sempre é bom, concorda? Para os que não conhecem XAML, é uma linguagem de construção de interface de aplicativos que o Windows Form nunca poderá ser e que o HTML sempre sonhou ser.

Como disse arteriormente, para atingir o objetivo de 1 app — N dispositivos, a Microsoft pensou em três frentes: interface, núcleo do Windows e API (você pode ler sobre núcleo e API unificada neste artigo). Neste artigo nos focaremos na interface, mais precisamente em XAML (observação: você também pode criar interfaces com DirectX ou HTML). E, no âmbito do XAML, a Microsoft nos oferece o seguinte tripé: Effective Pixels, Adaptive Controls e novas formas de fluxo. Comecemos pela bruxaria chamada Effective Pixels.

Effective Pixels

Universal App - calculando distância visual

(EPX leva em conta a provável distância entre os olhos do usuário e a tela do dispositivo)

O conceito por trás do EPX (acrônimo para Effective Pixels) é que o pixel, na visão do programador, deixa de ser REAL e passa a ser CALCULADO pelo sistema, automaticamente, levando em consideração o dispositivo, a resolução, o DPI e principalmente a provável DISTÂNCIA que o usuário está ao olhar a tela do dispositivo. Dessa forma, o sistema consegue exibir uma mesma informação em vários dispositivos diferentes, evitando distorções visuais ou exigindo que o programador se preocupe com isso. Na verdade, para o programador, esse cálculo é transparente.

Universal App - pixel real x pixel efetivo

(pixel real X pixel efetivo, 1epx equivalendo a um bloco de 4x4px)

Todo o sistema será medido em EPX, e não mais em píxeis como é atualmente. Se você programador define que uma caixa terá 50epx de largura, o sistema calculará automaticamente o que realmente significam esses 50epx de acordo com o dispositivo onde seu aplicativo será executado, aumentando ou diminuindo o bloco de píxeis que compõem o pixel efetivo.

Universal App - comparando pixel real x pixel efetivo

(na esquerda, uma caixa com largura de 50px — sistema tradicional de píxeis reais)
(na direta a mesma caixa com 50epx de largura, calculada automaticamente pelo sistema)

Por causa do DPI, a partir do momento que a resolução aumenta, a figura desenhada no sistema tradicional de píxeis tende a ficar menor, tornado mais difícil a sua visibilidade e exigindo do programador algum cálculo de compensação. Imagine o esforço de se preocupar com dezenas de resoluções e prever se o usuário está rodando seu aplicativo no celular a um palmo de distância dos olhos ou se na televisão conectada a um Xbox a 3 metros de distância.

Agora, com EPX, as caixas estão com tamanho uniforme, independentes da resolução ou DPI do dispositivo. O sistema calculou as caixas para ocuparem o mesmo espaço, pois independente da resolução REAL destes dispositivos eles ainda são celulares que serão usados perto dos olhos. Resumindo: você define <TextBlock FontSize=”24"/> e o sistema automaticamente aumentará ou diminuirá o FontSize de acordo com o dispositivo, deixando-o menor se for em um smartphone próximo aos olhos ou aumentando-o se for em uma televisão na parede.

O mais incrível é que, em termos de código, o desenvolvedor XAML não precisará fazer nada de diferente! Continue usando FontSize, Width, Margin, Padding e etc como de costume, se focando apenas na legibilidade da informação e ignorando resolução, escala e DPI. Como eu disse anteriormente: bruxaria.

Adaptive Controls

Universal App - adaptive control

(controle se adaptando automaticamente ao dispositivo)

De nada adiantaria EPX se os controles visuais fossem dependentes do ambiente, com versões separadas para cada dispositivo. Dessa forma a Microsoft uniu os controles XAML do Windows Phone com os do Windows Store e os refez para que fossem ADAPTIVOS. Agora temos à nossa disposição um pacote consistente de controles que funcionam igual, porém diferente, em todos os dispositivos Windows 10.

Iguais mas diferentes. Essa é a melhor definição para os controles adaptivos. Para o programador o que importa é a FUNÇÃO do controle. Não interessa se um controle está rodando no celular ou PC, ele cumprirá seu objetivo sem alterações no código, e essa é a parte igual. Mas o controle será capaz de observar o ambiente ao seu redor e se comportará da melhor maneira possível para aquele ambiente, e essa é a parte diferente, adaptiva.

Universal App - adaptive controls

(menu pop-up e calendário, se adaptando ao ambiente de uso mouse X touch)

E essa adaptação não se resume apenas a espaço na tela. Ambiente significa dispositivo, espaço, forma de interação, identidade visual. Tomemos como exemplo a interação touch versus mouse. O controle será capaz de perceber seu ambiente e se moldar a ele, entregando ao usuário a melhor forma possível de uso do controle. Para você o que importa apenas é declarar o controle no seu XAML e esperar o retorno do seu uso, independente se o usuário está usando os dedos na pequena tela do smartphone, o mouse do PC em um monitor de 21' ou o controle do Xbox.

A lista de novos controles inclui RelativePanel, Calendar, SplitView e Pivot do Windows Phone.

Fluxo

Universal App - resoluções

A partir do momento que o sistema recalcula as medidas com EPX e os controles se adaptam ao ambiente, a sua maior preocupação passa a ser distribuir as informações pela área disponível. Não há mágica aqui: um smartphone tem menos área disponível do que o desktop, e é sua responsabilidade direcionar o fluxo de informações por toda a área afim de melhor aproveitar o espaço disponível.

Tenha em mente que a forma de uso de um smartphone não é a mesma de um desktop. Normalmente o usuário espera que, no smartphone, as informações fluam verticalmente (possibilitando rolagem com apenas um dedo, por exemplo), enquanto no tablet ou desktop o fluxo segue colunas verticais dispostas lado a lado horizontalmente. Além disso, deve-se levar em conta as possíveis orientações de retrato ou paisagem.

Universal App - desenhando layouts

(desenhando layouts prevendo vários dispositivos e orientações)

Se você está familiarizado com XAML já conhece os painéis tradicionais como Grid e StackPanel. Uma forma tradicional de responder à alteração de orientação da tela é trocar, por código em tempo de execução, os valores de Grid.Column e Grid.Row de um elemento ou Orientation do StackPanel. Bom, essas formas continuam disponíveis, mas para alterar o fluxo dinamicamente com mais facilidade a Microsoft incluiu novidades, como RelativePanel e Visual State com AdaptiveTrigger.

Universal App - RelativePanel1

Veja estes controles. Com Grid seria fácil conseguir essa disposição, mas muito trabalhoso reposicioná-los em resposta ao redimensionamento da janela ou mudança da orientação da tela. Agora, observe o código abaixo usando RelativePanel:

[sourcecode language=”xml”]
<RelativePanel>
<TextBox x:Name=”textBox1" Text=”textbox” Margin=”5"/>
<Button x:Name=”blueButton” Margin=”5" Background=”LightBlue” Content=”ButtonRight” RelativePanel.RightOf=”textBox1"/>
<Button x:Name=”orangeButton” Margin=”5" Background=”Orange” Content=”ButtonBelow” RelativePanel.RightOf=”textBox1" RelativePanel.Below=”blueButton”/>
</RelativePanel>
[/sourcecode]

Quem é do meio HTML/CSS já percebeu a semelhança com STYLE FLOAT. Dentro de um RelativePanel os controles se posicionam relativamente a outro controle, nesse caso o botão azul se coloca ao lado direito da caixa de texto enquanto o botão laranja se posiciona abaixo do botão azul. Mas vamos supor que o usuário alterou o tamanho da janela no desktop ou rotacionou o tablet e seu aplicativo precisa responder corretamente a esse evento, seja reposicionando elementos, seja ocultando elementos, seja alterando outras propriedades. Para isso entra em cena Visual State com AdaptiveTrigger:

[sourcecode language=”xml”]
<Grid Background=”{ThemeResource ApplicationPageBackgroundThemeBrush}”>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name=”wideView”>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth=”720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target=”best.(RelativePanel.RightOf)” Value=”free”/>
<Setter Target=”best.(RelativePanel.AlignTopWidth)” Value=”free”/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name=”narrowView”>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth=”0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target=”best.(RelativePanel.Below)” Value=”paid”/>
<Setter Target=”best.(RelativePanel.AlignLeftWithPanel)” Value=”true”/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

</Grid>
[/sourcecode]

Universal App - RelativePanel2

(elemento BEST do lado direito do elemento FREE)

Na imagem acima temos as seções BEST, PAID e FREE que são controles que exibem uma lista de aplicativos em destaque, pagos e gratuitos. Observe que BEST está ao lado direito de FREE. No código-exemplo XAML foram criados dois estados visuais: wideView e narrowView. Cada estado tem um gatilho. O estado wideView será acionado quando a propriedade MinWindowWidth for no mínimo 720, e narrowView é o estado padrão de visualização, pois o gatilho verifica se MinWindowWidth é no mínimo zero.

MinWindowWidth é uma das propriedades do AdaptiveTrigger e se refere ao tamanho mínimo da JANELA do aplicativo. Se o aplicativo estiver sendo executado em uma área/janela com no mínimo 720 pixeis de largura então o primeiro gatilho será verdadeiro e disparado. Quando o usuário rotacionar o dispositivo ou redimensionar a janela então a largura da área será alterada, e se a largura da área for menor que 720 fará com que o primeiro gatilho se torne falso, dando chance ao sistema para verificar e executar os gatilhos subsequentes, no caso narrowWide, que sempre será verdadeiro.

Uma vez que algum gatilho retorne verdadeiro o sistema executará as alterações de propriedades definidas na seção Setters. No exemplo acima é alterado o posicionamento relativo do elemento BEST em relação aos elementos FREE e PAID. Quando em wideView, BEST estará à direita e alinhado com o topo de FREE. Quando em narrowView (como visto na imagem abaixo) BEST estará abaixo de PAID e alinhado à esquerda do painel.

Universal App - RelativePanel2

(elemento BEST abaixo do elemento PAID)

Qualquer propriedade pode ser alterada dentro de Setter, não apenas as relacionadas a posicionamento. Por exemplo, dependendo do gatilho você pode usar Setter para ocultar uma imagem , alterar a Orientation de um StackPanel, alternar entre Grid.Column/Row ou mesmo trocar fontes e cores! E se AdaptiveTrigger não for suficiente, crie suas classes Triggers personalizadas. As opções são ilimitadas. Você percebeu que não foi necessário usar nenhum código e que toda a lógica pode ser exposta usando apenas XAML? Isso é perfeito para separar interesses e usar padrões como MVVM.

Dependendo do seu aplicativo, ao responder ao redimensionamento da janela você pode redimensionar controles, reposicioná-los, alterar seu fluxo ou mesmo criar uma página XAML específica para cada situação! Tenha em mente que não existe A forma ideal, e que quem decide como seu aplicativo deve se comportar é você, e não o sistema.

UniversalApp - tooling

(testando resoluções direto na janela de diagramação do XAML)

Pensa que acabou? Para facilitar ainda mais a criação de Adaptive UI o Visual Studio vem com várias novidades como XAML Inspector em tempo de execução, um novo e mais poderoso Blend e várias opções de teste de resoluções direto na diagramação do XAML, como na imagem acima.

Janela de Oportunidades

Nestes dois artigos vimos como a Microsoft trabalhou para nos entregar uma plataforma coesa, unificada. O objetivo é que nossos apps tenham um alcance de usuários nunca antes visto em nenhuma outra plataforma de apps, com o mínimo esforço por parte dos programadores. Tudo está unificado, da criação à instalação, da loja aos pagamentos, da experiência de usuário aos dispositivos. Ao criar um único app e o disponibilizá-lo para bilhões, de forma segura e prática, podemos realizar o sonho utópico não conseguido nem mesmo com HTML.

Faço aqui um acompanhamento da estória do desenvolvimento de programas:

  • antigos programas desktop: alta performance e recursos, difícil distribuição e problemas de pirataria;
  • sites como programas: baixa performance e recursos, distribuição e pirataria resolvidas;
  • apps universais: alta performance e recursos, distribuição e pirataria resolvidas.

As apps universais são naturalmente o próximo passo no desenvolvimento de programas. As pessoas passam mais tempo nas versões nativas do Facebook e Twitter ao invés das versões móveis por reconhecerem a melhor experiência proporcionada pelos apps nativos. O WhatsApp nem mesmo versão Web se preocupou em fazer. Os usuários dizem, com todas as letras, que querem performance, recursos e praticidade. E é isso que as apps universais podem entregar.

No Windows 10 a Microsoft trouxe de volta o menu Iniciar clássico, onde o usuário fixará seus apps universais preferidos. Espero que os meus estejam ali. E você, já começou a desenvolver o próximo app que alcançará milhões?

--

--