Fevereiro de 2016

Volume 31 – Número 2

Windows 10 – Aplicativos da Plataforma Universal do Windows para Desenvolvedores Web

Por Tim Kulp | Fevereiro de 2016

Como programador Web para empresas, você tem um conhecimento profundo de HTML, CSS e JavaScript. Você pode criar aplicativos Web que se adaptam ao tamanho da tela, ao mesmo tempo que mantém a funcionalidade de todos os seus navegadores ou dispositivos com suporte. As mesmas habilidades que você usa para dar leveza à Web podem ser usadas para criar aplicativos da UWP (Plataforma Universal do Windows). Se estiver criando área de trabalho, dispositivo móvel ou qualquer plataforma para o Windows 10, as lições que você aprendeu com os aplicativos Web adaptáveis entre navegadores oferecem um bom ponto de partida para começar com a UWP.

Neste artigo, vou explorar como usar o conhecimento de desenvolvimento para a Web, desde a criação de aplicativos entre navegadores a aplicativos de UWP flexíveis que funcionam em qualquer dispositivo com Windows. Para isso, começo analisando como os princípios fundamentais de criação de interfaces dinâmicas são traduzidos de CSS e HTML para UWP. Em seguida, vou fazer uma análise com o VisualStates e os Modos de exibição XAML para estruturar seu aplicativo com base nos recursos específicos do dispositivo. Por fim, uso o código adaptável para identificar dispositivos com base em como o bom e velho JavaScript é usado para identificar navegadores específicos.

Por que usar XAML para Desenvolvedores Web?

Neste artigo, vou criar paralelos de desenvolvimento para a Web para XAML. É provável que os desenvolvedores Web já tenham muita habilidade com HTML/CSS/JavaScript e desejem criar uma UWP com essa habilidade. Se você adora HTML e JavaScript, pode continuar a usá-las sem problema. Se você for novo em UWP e não souber por onde começar, a XAML é uma ótima ferramenta de ajuda graças à sua natureza fortemente tipada.

Um exemplo comum disso é usar um layout baseado em grade em XAML versus HTML. Em XAML, a criação de um layout de grade começa com a adição de um controle de grade, definindo as colunas e as linhas e atribuindo cada controle dentro da grade a uma célula ou linha específica. Em HTML, há muitas maneiras de criar um layout de grade como:

  • Usar floats com altura e largura definidas a fim de criar células com espaço para iniciar uma nova linha
  • Usar exibição de grade no elemento contêiner com todos os elementos filhos que tenham coluna e linha definidas
  • Usar uma tabela com elementos tr e td

O que é implementado depende de seu conhecimento de CSS ou HTML, e essas abordagens não ajudarão você com ferramentas do tipo IntelliSense como o controle de grade ajudará em XAML. Os controles com rigidez de tipos de XAML facilitam saber como criar uma interface de usuário por meio do IntelliSense, o que ajuda muito desenvolvedores iniciantes na UWP.

O código com rigidez de tipos também traz muitas vantagens na hora de solucionar problemas. Em HTML/CSS/JavaScript, os desenvolvedores contam com muita flexibilidade para contornar as regras relacionadas às exigências do aplicativo usando um código sem rigidez de tipos. Isso é ótimo para criar aplicativos, mas pode ser um pesadelo para dar suporte a eles. Solucionar problemas de código sem rigidez de tipos pode se tornar um desafio quando os tipos mudam ou os objetam mudam dinamicamente. Como desenvolvedor para empresas, criar aplicativos é divertido, mas alguma hora alguém vai ter que manter o aplicativo funcionando. A capacidade de navegar com facilidade pela funcionalidade de um aplicativo usando objetos com rigidez de tipos e IntelliSense ajuda a equipe de suporte a entender o aplicativo.

Se você é um apaixonado por HTML/CSS/JavaScript, a UWP oferece uma plataforma para você usar seu código existente a fim de criar aplicativos incríveis. HTML/CSS/JavaScript e XAML são ferramentas ótimas com muitos prós e contras. Existem dois artigos que explicam por que um autor prefere XAML a JavaScript (bit.ly/1NxUxqh) e outro prefere JavaScript a XAML (bit.ly/1RSLZ2G). Eu adoro HTML para aplicativos Web, mas sugiro que você explore o XAML, principalmente se for novo em UWP, para aprender seus controles e manter os custos de suporte baixos para a sua equipe usando códigos com rigidez de tipos que se integram sofisticadamente ao IntelliSense, se divertindo e aprendendo algo novo.

Criando em cima do que você já sabe

A UWP tem muitas semelhanças com os princípios fundamentais de design da Web. As ideias básicas, como separação de interesses em desenvolvimento para a Web entre HTML e JavaScript, se traduzem em UWP para XAML e arquivo code-behind XAML.cs. Toda a lógica vai para o code-behind, enquanto toda a apresentação é mantida no arquivo XAML (assim como toda a lógica vai para o JavaScript enquanto a apresentação está em HTML com a ajuda do CSS). Além disso, muitos aplicativos Web modernos aproveitam estruturas como Knockout e AngularJS para implementar a associação de dados por meio do padrão de design MVVM (Model-View-ViewModel). Em geral, o conhecimento dessas estruturas e do MVVM são a base para entender a vinculação de dados na UWP. Se por um lado a sintaxe é diferente entre o desenvolvimento para a Web e para UWP, por outro, no que diz respeito a conceitos básicos, os desenvolvedores Web contam com uma base sólida para criar aplicativos compatíveis entre vários dispositivos, navegadores e recursos.

Existem muitas diferenças entre o desenvolvimento para a Web e a UWP que não serão tratadas neste artigo, como gerenciamento de estado e armazenamento de dados. Neste artigo, focarei na criação da interface de usuário, garantindo que o aplicativo possa interagir com o dispositivo no qual ele está sendo executado.

Posicionamento: Float e Clear para RelativePanel

Em HTML, você determina o posicionamento de cada elemento em função de onde ele se encontra no Document Object Model. HTML é uma linguagem de cima para baixo, com cada elemento sendo processado na ordem do primeiro elemento declarado para o último. Quando o CSS foi lançado, ele permitia que os elementos tivessem layouts sofisticados baseados na configuração do estilo de exibição do elemento (em linha, bloco e assim por diante), da posição (relativa ou absoluta), assim como do float e clear. Com o float, os desenvolvedores Web poderão retirar um elemento HTML do fluxo de cima para baixo e colocar o elemento à esquerda (float: left) ou à direita (float: right) do elemento contido nele.

Imagine um layout simples incluindo cabeçalho, conteúdo principal, barra lateral e rodapé. O float instrui o navegador a renderizar a barra lateral na borda direita do contêiner e a renderizar o conteúdo principal na borda esquerda do contêiner. Com o float, os elementos se posicionarão lado a lado, à esquerda ou à direita, dependendo do valor de float especificado. O clear é usado para parar o float dos elementos e retornar para o fluxo padrão de cima para baixo do HTML. A Figura 1 mostra um exemplo de como usar float para criar um layout simples.

Figura 1 Usando float para criar um layout simples

div {
  width: 100%;
}
mainContent {
  width: 60%; float: left;
}
  sidebar{
  width: 40%; float: right;
}
clearer {
  clear: both;
}
CSS for design
<header>
</header>
<div>
  <section class="content"></section>
  <section class="sidebar"></section>
  <div class="clearer"></div>
</div>
<footer>
</footer>
HTML for design

Onde os desenvolvedores Web usam float e clear para criar um layout, a UWP fornece um controle chamado RelativePanel (painel relativo em português) que, como o nome sugere permite que um layout seja definido usando relacionamentos relativos com outros controles. Como o float, os RelativePanels permitem que os desenvolvedores gerenciem como os controles são posicionados em relação ao controle de âncora. As classes CSS são usadas para determinar o posicionamento dos elementos na página da Web. Para replicar o mesmo layout, use o RelativePanel e as propriedades anexadas do RelativePanel dentro dos controles:

<RelativePanel>
  <!-- Header is the anchor object for the relative panel -->
  <TextBlock Text="Header" Name="tbHeader"></TextBlock>
  <TextBlock Text="Content" RelativePanel.Below="tbHeader"
    Name="tbContent"></TextBlock>
  <TextBlock Text="SideBar" RelativePanel.RightOf="tbContent"
    RelativePanel.Below="tbHeader" Name="tbSideBar"></TextBlock>
  <TextBlock Text="Footer" RelativePanel.Below="tbSideBar"
    Name="tbFooter"></TextBlock>
</RelativePanel>

Neste bloco de código, o posicionamento de cada controle é relativo à posição do controle de âncora (neste caso, a âncora e o cabeçalho TextBlock). Com o Relative Panel, cada controle pode ser atribuído para o local onde o controle deveria aparecer na tela em relação aos outros controles. Onde os desenvolvedores Web usariam float: left, os desenvolvedores da UWP usariam RelativePanel.LeftOf ou Relative­Panel.RightOf (para float: right) Embora isso se pareça com o uso do float, não existe um conceito de uso do clear para voltar ao fluxo normal. Em vez disso, apenas anote que algo está abaixo de um elemento anterior. Isso simplifica questões relativas à solução de problemas de layout, pois gerenciar floats e clears pode ser complicado para desenvolvedores que não possuem muita habilidade com CSS. O RelativePanel oferece uma forma declarativa de especificar onde um controle deverá aparecer em relação a outros controles. Quando o RelativePanel estiver fechado, o aplicativo retornará ao seu fluxo normal de renderização de XAML (que é de cima para baixo como o HTML).

Dimensionamento: Porcentagens e pixels

Criar um aplicativo Web dinâmico por meio de redimensionamento significa usar tamanhos relativos para os elementos. Ao usar um layout de página com cabeçalho, conteúdo, barra lateral e rodapé, imagine que essa interface de usuário foi originalmente criada para uma tela de área de trabalho. Primeiro, os desenvolvedores Web identificariam a largura de pixel ideal para a página desse layout. No exemplo, a largura da página será de 1000px. Como cada elemento é criado no design, o elemento é criado de acordo com a largura do pixel, tendo em consideração o contêiner de 1000px. Em HTML, a seção de conteúdo seria de 800px de largura, enquanto a seção da barra lateral seria de 200px de largura. Usando a fórmula: destino/contexto = porcentagem, a seção do conteúdo equivale a 80% do contexto (enquanto que o contexto = a página de 1000px), ao passo que a barra lateral é de 20%.

O uso das porcentagens do design da Web permite o redimensionamento do layout conforme o contêiner é redimensionado. Nesse caso, se o objeto da página de 1000px for redimensionado pelo usuário para somente 659px, o conteúdo e a barra lateral seriam redimensionados, respectivamente, para 527px e 131px. Da mesma forma, os estilos de criação para usar em no lugar de um ponto específico ou tamanhos de pixel, permitem dimensionar a fonte de acordo com o contexto. Essas práticas ajudam a garantir que um design mantenha o dimensionamento proporcional, independentemente do tamanho da janela.

Embora o uso dos cálculos de porcentagem pode parecer simples, existem outros fatores que estão envolvidos na maneira como os elementos são dimensionados, como a densidade de pixel do dispositivo e a orientação, que adicionam um elemento de imprevisibilidade ao seu design. A UWP simplifica o dimensionamento usando o conceito de “pixel efetivo” para todas as medições. Um pixel efetivo não é a mesma coisa que um pixel único. Os pixels efetivos usam o algoritmo de dimensionamento da UWP para saber como representar um pixel efetivo, com base na distância padrão do dispositivo em relação ao usuário e da densidade do pixel.

Por exemplo, um Surface Hub teria uma densidade de pixel muito maior do que um tablet ou um celular. Os desenvolvedores da UWP precisam criar somente para pixels efetivos em ferramentas como o Blend e permitir que o algoritmo de dimensionamento trate dos cálculos complexos necessários para reduzir ou expandir adequadamente. É importante não se esquecer do seguinte: pixels eficazes devem ser múltiplos de quatro. Com base em como o algoritmo de dimensionamento funciona, usar múltiplos de quatro garantirá bordas nítidas conforme a interface de usuário é dimensionada.

ViewStates e consultas de mídia

No desenvolvimento para Web, o CSS fornece a informação de layout para um determinado aplicativo. Criar um aplicativo com porcentagens permite que ele seja redimensionado, mas, a certa altura, o design precisa ser interrompido e corrigido para atender às demandas de alteração da exibição. Um layout criado para um dispositivo móvel, como um tablet, não será o mesmo criado para um dispositivo com apresentação de mais de 80 polegadas, como o Surface Hub. Uma analogia mais antiga para design da Web é o caso de um usuário desejar imprimir um design baseado em tela. O CSS permite que os designers corrijam o dilema da tela de impressão com consultas de mídia CSS. Enquanto o usuário imprimia o design, o navegador usava a impressão CSS em vez da tela CSS. Como o design de Web dinâmico tem evoluído, as consultas de mídia também têm aumentado para dar suporte às informações mais detalhadas. Vejamos um exemplo de uma consulta de mídia CSS:

<link type="text/css" rel="stylesheet" 
  href="styles/719style.css"
  media="screen and (max-device-width: 719px)"/>

Nessa consulta, o arquivo 719style.css será usado se a mídia exibindo o aplicativo Web for uma tela com um dispositivo de largura inferior ou igual a 719px. Por exemplo, essa consulta de mídia pode ser usada para limpar os valores de float e apresentar o conteúdo e os elementos da barra de ferramentas em um design empilhado em contraste com um lado a lado. O uso de consultas de mídia permite que desenvolvedores Web personalizem a exibição com base no tamanho da tela, na resolução, na orientação e em muitas outras opções (consulte a lista completa para CSS3 em bit.ly/1riUA2h).

Na UWP, o ViewStateManager pode ser usado como consultas de mídia para alterar o design do aplicativo com base em parâmetros definidos. O VisualStateManager contém um ou mais VisualStateGroups, que é um objeto de contêiner de múltiplos ViewStates. Cada ViewState contém setters (quais propriedades são atualizadas para cada controle) e disparadores (o que faz os setters mudarem). O ViewStateManager gerencia os disparadores para saber quando aplicar os valores de setter de um ViewState específico. Em termos de CSS, os disparadores são como consultas de mídia e os setters são os valores de estilo dentro da folha de estilo referenciada na consulta de mídia. Veja o exemplo na Figura 2.

Figura 2 Controles de reposição baseados nos gatilhos do VisualState

<VisualStateManager.VisualStateGroups>
  <VisualStateGroup x:Name="ResponseStateGroup">
    <VisualState x:Name="LessThan720">
      <VisualState.Setters>
      <Setter Target="tbSideBar.(RelativePanel.Below)" Value="tbContent"/>
        <Setter Target="tbSideBar.(RelativePanel.RightOf)" Value=""/>
      </VisualState.Setters>
      <VisualState.StateTriggers>
        <AdaptiveTrigger MinWindowWidth="1"/>
      </VisualState.StateTriggers>
    </VisualState>
    <VisualState x:Name="GreaterThan720">
      <VisualState.Setters>
        <Setter Target="tbSideBar.(RelativePanel.Below)" Value="tbHeader"/>
        <Setter Target=" tbSideBar.(RelativePanel.RightOf)" Value="tbContent"/>
      </VisualState.Setters>
      <VisualState.StateTriggers>
        <AdaptiveTrigger MinWindowWidth="720"/>
      </VisualState.StateTriggers>
    </VisualState>
  </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

Neste código, dois VisualStates são configurados. O ViewState LessThan720 dispara quando a largura da janela é de 1px a 719px. Quando a janela expande para 720px ou mais, o ViewState GreaterThan720 dispara. Todos esses ViewStates trabalham com as configurações RelativePanel do controle tbSideBar. Se o tamanho da janela for inferior a 720, significa que a tela não é grande o suficiente para dar suporte a um design cujo conteúdo esteja ao lado da barra lateral. Nesta situação, o ViewState LessThan720 dispara, o que faz com que a barra lateral empilhe embaixo do TextBlock do conteúdo principal. Isso é como usar a consulta de mídia, na qual eu posso definir o float: nenhum em um arquivo LessThan719.css.

Assim como as consultas de mídia, os ViewStates podem ser usados para reposicionar ou rearquitetar controles com base nos disparadores. Quando mais complexa a interface vai tornando, mais complicado pode ficar o gerenciamento de ViewStates e ViewStateGroups. Gerenciar mudanças complexas de ViewState é a coisa mais fácil com o Blend for Visual Studio 2015. Com o editor do Blend, você pode criar novos VisualStates e ver as mudanças no design do aplicativo ao longo do processo. O Blend escreverá todo o XAML por você e fará com que todos os dados necessários para disparar a mudança do VisualState sejam fornecidos. A Microsoft Virtual Academy possui ótimos vídeos passo a passo sobre como usar o Blend para gerenciamento de ViewState em bit.ly/1P94e32.

Usando Modos de Exibição para rearquitetar a experiência

Às vezes, o site para celular apresenta uma interface de usuário diferente devido à diminuição de casos de uso ou a mudanças no foco dos serviços do site em relação à experiência completa da área de trabalho. Neste cenário, os desenvolvedores Web adaptariam o conteúdo ao uso móvel para oferecer uma experiência mais dinâmica, ou para destacar os recursos do dispositivo móvel. Usando vários métodos de detecção, os desenvolvedores Web podem redirecionar os usuários para uma experiência rearquitetada adaptada ao seu dispositivo, normalmente conhecido como o site m.webapp.com.

A UWP oferece a mesma capacidade pelos Modos de Exibição. Dependendo do aplicativo, o trabalho com diferentes famílias de dispositivos poderia desencadear uma diferença gritante na interface do usuário, para a qual o ViewStateManager não seria a ferramenta adequada. Os Modos de exibição permitem que os desenvolvedores aproveitem o código de back-end existente com uma nova interface de usuário XAML. Você pode simplificar a função Usando Modos de Exibição por meio de ViewModels bem estruturados, enquanto pode aproveitar um único objeto ViewModel em diversos Modos de Exibição. Conhecimentos em Knockout ou AngularJS poderão ajudar desenvolvedores Web a criar ViewModels adequados em UWP para UXs adaptados a uma família específica de dispositivos.

Você define uma Exibição para um dispositivo específico criando uma pasta dentro da pasta de Modos de Exibição do aplicativo.

Dentro da pasta Modos de Exibição, crie uma nova pasta chamada Device­Family-Mobile. Isso diz à Modern Resource Technology para usar a exibição MainPage.xaml encontrada na pasta DeviceFamily-Mobile quando a MainPage é solicitada em um dispositivo na família de dispositivos móveis (como um celular). Se a solicitação para a MainPage vier de qualquer outra família de dispositivo, a resposta será a MainPage padrão. Esta funcionalidade permite que os desenvolvedores da UWP criem interfaces de usuários direcionadas para casos de uso que são exclusivos para famílias de dispositivos Windows específicas.

Código adaptável

Na criação de aplicativos Web, nem todos os navegadores são iguais. Em uma empresa, é provável que você tenha normas corporativas, mas ao desenvolver para usuários externos, a complexidade vem de vários sistemas operacionais, tipos de navegador e versões. Os desenvolvedores Web possuem muitos truques na manga para lidar sutilmente com essas diferenças. Bibliotecas como Modernizr (modernizr.com) tornaram o tratamento desse tipo de complexidades mais fácil, mas habilitar funcionalidades baseadas em um dispositivo ou navegador não é novidade para os desenvolvedores Web.

Criar aplicativos para UWP podem contar com as mesmas complexidades de uma funcionalidade entre navegadores. Imagine um aplicativo para anotações no qual os usuários possam adicionar imagens às suas notas. O aplicativo poderia aproveitar a funcionalidade de câmera interna de um celular para tirar uma foto ou apenas para permitir que os usuários visualizem imagens que já existem em seus dispositivos.

A primeira etapa no uso de capacidades específicas para dispositivos é garantir que as APIs de extensão certas sejam incluídas no projetos. Por exemplo, no aplicativo de anotação, os botões de hardware precisariam estar acessíveis em um celular. Para usar esses botões, você deve adicionar uma referência às extensões móveis do Windows para a UWP. Isso é feito adicionando uma referência no projeto (como qualquer outra referência) e selecionando Universal do Windows e Extensões. Você verá uma lista de extensões possíveis como as extensões para área de trabalho, dispositivos móveis e equipe (para Surface Hub). Selecione quais extensões você precisa adicionar ao projeto e clique em OK.

Enquanto o JavaScript detectaria as capacidades do navegador por uma série de verificações do navegador, na UWP, o aplicativo verifica a presença da API necessária através do método IsTypePresent. No aplicativo de anotação, verifique se o botão de hardware usa a câmera por meio do seguinte código:

string apiName = "Windows.Phone.UI.Input.HardwareButtons";
if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent(apiName))
{
  Windows.Phone.UI.Input.HardwareButtons.CameraPressed +=
    HardwareButtons_CameraPressed;
}

Este código pequeno permite que o aplicativo direcione as capacidades específicas do dispositivo adicionado através das APIs de extensão. Ao envolver a declaração do manipulado de evento CameraPressed com o método IsTypePresent, você garante que não vai tentar registrar o manipulador de evento quando a API não estiver presente. Existem ferramentas que ajudam a garantir que as verificações de API ocorrem de forma a não deixar que o aplicativo falhe quando a API não está presente. PlatformSpecific é um pacote NuGet excelente que simplifica a identificação e o envolvimento de qualquer referência com uma extensão API que não tenha sido primeiramente validada pelo método ApiInformation.IsTypePresent. Saiba mais sobre este pacote NuGet no site GitHub para PlatformSpecific em bit.ly/1GvhkF0.

Assim como no desenvolvimento Web, às vezes uma versão específica do navegador precisa ser direcionada para um cliente ou padrão corporativo. Nessas situações, os desenvolvedores Web precisam focar na configuração de um navegador específico que pode não corresponder com o que o resto da Internet está usando.

De forma semelhante, os desenvolvedores UWP precisam direcionar contratos específicos de uma extensão API para manter um código existente. Isso é muito útil em aplicativos para empresas, nos quais a equipe de operações de TI poderiam ter um loop rápido e um loop lento para implantar atualizações nos computadores dos funcionários. O loop rápido poderia obter um novo recurso ótimo de alguma extensão API que deve ser implementada no aplicativo imediatamente. Nesta situação, os usuários do loop lento ainda precisam de sua funcionalidade. Usando IsApiContractPresent, a UWP pode verificar que a extensão API está disponível e que a versão específica esperada está disponível antes de executar o código:

if(Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent(apiName, 3))
{
  newKillerFunction();
}

Neste segmento de código, o aplicativo executará somente a newKillerFunction se o apiName fornecido estiver na versão 3. Se a versão for inferior à 3, a newKillerFunction não será executada. Se uma versão superior estiver presente (por exemplo, versão 4), a newKillerFunction será executada.

Conclusão

O desenvolvimento da UWP aproveita muitas das habilidades e do conhecimento que os desenvolvedores Web usam para criar aplicativos Web dinâmicos e entre navegadores. Desenhar o layout, dando resposta às diferenças nas telas (tanto estáticas quanto dinâmicas), assim como as capacidades do sistema, são todas práticas comuns para desenvolvedores Web lidarem com o mundo selvagem dos navegadores da Web. Aplicando essas habilidade no desenvolvimento da UWP ajudará na criação de UXs valiosos que se adaptam ao tamanho da tela, ao dispositivo e aos recursos.


Tim Kulpé um arquiteto técnico sênior que vive em Baltimore, Md. Ele é desenvolvedor de Web, dispositivos móveis e de UWP, assim como escritor, pintor, pai e “aspirante a cientista louco”. Encontre ele no Twitter: @seccode ou no LinkedIn: linkedin.com/in/timkulp.

Agradecemos ao seguinte especialista técnico da Microsoft pela revisão deste artigo: Kevin Hill