Aplicativos modernos

Dominando controles e configurações nos aplicativos da Windows Store criados com JavaScript

Rachel Appel

Rachel AppelExcelentes experiências de usuários apresentam dados para os usuários de maneira natural e intuitiva, independentemente do fator forma. A apresentação de dados e conteúdo exige APIs, controles e ferramentas atualizadas para a criação de experiências modernas. Nos aplicativos da Windows Store, a quantidade de código necessária e a complexidade dos controles dependem do tipo de aplicativo criado, independentemente de ele ser um jogo, um aplicativo de produtividade, social ou financeiro. Os controles da Biblioteca do Windows para JavaScript (WinJS) são fáceis de dominar para qualquer desenvolvedor que estiver criando aplicativos da Windows Store com JavaScript, e é sobre eles que vamos discutir aqui.

O Windows 8 apresenta um novo paradigma e novos controles de interface de usuário

Os aplicativos da Windows Store têm aparência e se comportam de maneira muito diferente dos programas em execução em versões anteriores do Windows. Ocorreram algumas grandes renovações no Windows, começando com a nova página inicial, cheia de blocos dinâmicos como sua primeira interação com os aplicativos. Outras mudanças óbvias são que os aplicativos da Windows Store são executados em modo de tela inteira ou de exibição encaixada, colocando o conteúdo à frente e no centro, ao passo que os comandos e os menus ficam fora do campo de visão até que o usuário os solicite.

Os elementos de interface do usuário do Windows, como os botões para minimizar, maximizar e fechar, que eram abundantes, não existem mais nos aplicativos da Windows Store, pois os gestos de passar o dedo e tocar e os movimentos do mouse os tornaram inúteis. Para fechar um aplicativo, você precisa apenas passar o dedo ou o mouse de cima para baixo na tela. Até mesmo os menus não são mais um acessório fundamental na parte superior das telas. Nos aplicativos da Windows Store, os menus permanecem ocultos até que um gesto de passar o dedo ou o mouse os revele na parte inferior da tela, no AppBar, conforme exibido na Figura 1, que mostra um pequeno aplicativo de contagem regressiva como exemplo.


Figura 1 O AppBar na parte inferior do aplicativo

Como é possível ver na Figura 1, os menus estão ausentes e os elementos de comando são primeiramente elementos gráficos com algum texto, em vez dos tradicionais menus com texto primeiro e elementos gráficos ocasionais. Esses elementos também são do tamanho exato do dedo. Se precisar de mais espaço para as opções além da parte inferior, você pode colocar uma barra de navegação, que é simplesmente um AppBar, na parte superior da página.

A navegação em menus tradicionais do Windows pode ser muito difícil às vezes. Nós todos nos encolhemos de medo frente a um programa com um menu em cascata com 13 níveis, que faz com que você se esqueça do que estava procurando inicialmente. Em aplicativos da Windows Store, a navegação se entrelaça ao conteúdo, pois os gestos de toque e do mouse em itens de ListView invocam outras páginas. Os gestos de aperto e a tecla Control+roda do mouse ativam o zoom semântico (bit.ly/16IDtdi), que é um controle e um paradigma de navegação em aplicativos da Windows Store. O zoom semântico faz parte da listagem completa de controles do WinJS (bit.ly/w1jLM5).

Trabalhando com HTML e controles do WinJS

Existem dois tipos principais de controles em aplicativos da Windows Store que usam JavaScript: elementos HTML padrão e controles do WinJS. Os controles do WinJS são HTMLs combinados com JavaScript pré-compilado que amplia a maneira como os elementos HTML se parecem ou se comportam. Como eles são HTML, você pode estilizar os controles do WinJS com CSS. A Figura 2 é um exemplo de um controle do WinJS básico, o DatePicker do WinJS, que é um controle que abrange vários controles DropDown, representando o dia, o mês e o ano e mostrando o resultado padrão desse código:

    <span id="eventDate" data-win-control="WinJS.UI.DatePicker" />


Figura 2 Controle DatePicker do WinJS

É claro que o controle DatePicker na Figura 2 não possui estilo fora dos estilos padrão do WinJS, mas você pode alterar isso substituindo os seletores de CSS .win-datepicker-date, .win-datepicker-month e .win-datepicker-year do WinJS. Use o .win-datepicker para definir o estilo de todo o controle.

O motivo pelo qual o DatePicker (ou qualquer controle do WinJS) funciona dessa maneira é devido aos atributos data-* HTML5, ou seja, data-win-control. O atributo data-win-control significa o tipo de controle que o WinJS irá renderizar in loco, de forma que, quando você definir o valor do atributo data-­win-control como WinJS.UI.DatePicker, o controle renderizará os menus suspensos da Figura 2. O atributo data-win-options permite que você defina propriedades adicionais nos controles. Por exemplo, no DatePicker, você pode definir o data-win-options como a data de exibição padrão e intervalos de datas mínimo e máximo. Embora seja chamado de DatePicker, você pode alterar o controle para capturar a hora; por exemplo, horas, minutos e segundos.

Como o WinJS compila e renderiza a saída final do controle, o HTML em tempo de criação e o HTML em tempo de execução têm aparências bastante diferentes. A Figura 3 demonstra o HTML que o WinJS injeta no elemento host em tempo de execução. Isso pode ser visualizado no Explorador do DOM (Depurar | Windows | Explorador do DOM).

Figura 3 O DatePicker renderiza três menus suspensos preenchidos com as opções de data/mês/ano

    <span class="win-datepicker" id="eventDate" role="group"
       lang="en-US" dir="ltr" data-win-control="WinJS.UI.DatePicker">
    <select tabindex="0" class="win-datepicker-month win-order0"
       aria-label="Select Month">
    <option value="January">January</option>
    <option value="February">February</option>
    <option value="March">March</option>
    <option value="April">April</option>
    <!-- more <options> that show the other months -->
    </select>
    <select tabindex="0" class="win-datepicker-date win-order1"
       aria-label="Select Day">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
    <option value="4">4</option>
    <!-- more <options> that  show day numbers -->
    </select>
    <select tabindex="0" class="win-datepicker-year win-order2"
       aria-label="Select Year">
    <option value="1913">1913</option>
    <option value="1914">1914</option>
    <option value="1915">1915</option>
    <option value="1916">1916</option>
    <!—more <options> that show years -->
    <option value="2112">2112</option>
    <option value="2113">2113</option>
    </select>

O código de suporte a controles do WinJS, como o DatePicker, reside em um arquivo localizado em <raiz_do_projeto>\Referências\Biblioteca do Windows para JavaScript 1.0\js\ui.js, juntamente com alguns amigos importantes do WinJS. Observe que essa é a mesma referência de <script> que aquela necessária no elemento <head> das páginas de aplicativos da Windows Store, ou seja:

    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

Modifique esses arquivos por sua conta e risco, pois eles são compostos de código básico do WinJS.

Qualquer controle do WinJS, incluindo o DatePicker, é acessível em tempo de execução por meio de uma propriedade chamada winControl. O WinJS acrescenta propriedades filho à propriedade winControl em tempo de execução que são específicas para o tipo de controle do WinJS. Como exemplo, um ListView contém sua lista de itens ou você pode consultar um controle WinJS.UI.Ratings para a classificação selecionada pelo usuário. Você pode acessar a propriedade winControl do elemento desta maneira:

var control = document.getElementById("WinJSElementId").winControl

Os Buttons, CheckBoxes, RadioButtons, DropDowns, TextBoxes e semelhantes funcionam exatamente da mesma maneira que em qualquer página HTML simples antiga; entretanto, o namespace WinJS.UI está cheio de controles de interface de usuário para muitos cenários complexos, incluindo os controles de lista muito importantes.

Controles de lista e grade

Muitos tipos de aplicativos precisam apresentar dados em uma grade ou em uma lista e, por isso, é claro, existe um controle para esses cenários chamado ListView, que pode se renderizar como uma grade ou uma lista completa com agrupamentos e tamanhos de itens variáveis. O ListView não é apenas altamente flexível, ele também funciona perfeitamente na nova experiência do Windows fazendo coisas como o dimensionamento automático para se adaptar à tela e a colocação de itens de lista em linhas e colunas de tamanhos variados, dependendo da resolução e do tamanho da tela do dispositivo.

Embora a maioria dos outros controles do WinJS seja autônoma, os ListViews funcionam em conjunto com o HTML correspondente como um modelo. Isso significa que você deve configurar o HTML de modelo e o contêiner do próprio controle, conforme exibido na Figura 4. Observe que o atributo data-win-control do modelo e o atributo data-win-options do ListView contêm configurações que vinculam o ListView e seu modelo.

Figura 4 O HTML necessário para criar um ListView do WinJS

    <div id="maincontent">     
      <div id="listViewTemplate"
             data-win-control="WinJS.Binding.Template" >
        <div data-win-bind="style.background: color" class="win-item">
          <h1 data-win-bind=" innerText: daysToGo"></h1>
          <h2 class="subtitle" 
                 data-win-bind="innerText: eventTitle"></h2><br />
          <h2 class="subtitle-bottom" 
                 data-win-bind=" innerText: eventDate"></h2>
        </div>
      </div>
      <div id="listView" data-win-control="WinJS.UI.ListView"
        class="win-listview"
        data-win-options=
        "{ itemDataSource: Data.items.dataSource,
        itemTemplate: select('#listViewTemplate'),
        selectionMode: 'single'}">
      </div>
    </div>

A Figura 4 contém dois elementos <div>, um para o modelo com uma ID de listViewTemplate e o próprio ListView, chamado listView. O elemento listViewTemplate contém elementos filho que representam campos diferentes para cada item na lista ou na grade, como eventTitle ou eventDate. Ao observar o ListView na Figura 4, é possível verificar a propriedade itemDataSource definida como Data.items.dataSource, o que significa que Data é o namespace e items é um objeto WinJS.Binding.List preenchido com dados. Como o JavaScript funciona com dados de tipos flexíveis, tudo o que você precisa fazer é colocar uma matriz de objetos no construtor List e ele estará pronto para se associar aos controles ListView, semelhante a este código:

var items = [
  { eventTitle: "Rachel's Birthday", 
    eventDate: new Date(2014, 1, 13) },
  { eventTitle: "Rachel's BFF's Birthday", 
    eventDate: new Date(2013, 5, 29) }
];
var list = new WinJS.UI.list(events);

Como alternativa, você pode usar o método push para enviar itens por push para o objeto List, em vez de transmitir uma matriz para o construtor List. A melhor maneira de gerenciar dados em um ListView é expondo as opções relevantes (adicionar, excluir, entre outras) por meio de um controle AppBar.

AppBars e comandos

O conteúdo sobre o cromo é um importante princípio de design da Microsoft. Os AppBars são uma parte integrante desse princípio de design, pois ficam fora do campo de visão, esperando para apresentar suas opções quando você precisar delas. Em código, um AppBar é apenas um <div> que contém um ou mais elemento <button>, chamados “app bar commands”, com seus atributos data-win-control definidos como WinJS.UI.AppBarCommand. O recurso diferencial entre os comandos AppBar individuais está em data-win-options, como você já podia imaginar.

Ao analisar o data-win-options na Figura 5 de cada comando AppBar, é possível verificar a ID, o rótulo, o ícone e a seção de cada comando. Você pode atribuir botões do AppBar para a seção global do AppBar, que é exibida no canto inferior direito da tela do aplicativo, ou definir a opção da seção como “selection” para ser exibida no canto inferior esquerdo. A definição da opção de seção dos comandos AppBar como “selection” os torna contextuais, para serem utilizados quando um usuário selecionar um item no ListView passando o dedo ou clicando.

Figura 5 Criando um AppBar

    <!-- HTML -->
    <div id="appbar" class="win-appbar" 
           data-win-control="WinJS.UI.AppBar">
    <button data-win-control="WinJS.UI.AppBarCommand"
       data-win-options="{id:'deleteButton', 
        label:'Delete',
        icon:'delete', section:'selection'}" 
        type="button"></button>
    <button data-win-control="WinJS.UI.AppBarCommand"
       data-win-options="{id:'addButton', 
        label:'Add', icon:'add',
        section:'global'}" 
        type="button"></button>
    <button 
       data-win-control="WinJS.UI.AppBarCommand"
       data-win-options="{id:'refreshButton',
       label:'Refresh',
       icon:'refresh', 
       section:'global'}" 
       type="button"></button>
    </div>
    // JavaScript
    document.getElementById("addButton").addEventListener(
      "click", this.addButtonClick);
    document.getElementById("deleteButton").addEventListener(
      "click", this.deleteButtonClick);
    document.getElementById("refreshButton").addEventListener(
      "click", this.refreshButtonClick);

No arquivo JavaScript relacionado à página HTML, anexe ouvintes de eventos aos botões do AppBar da mesma maneira que você faria com qualquer outro elemento HTML. Não são necessários ouvintes para que o próprio AppBar seja exibido, pois ele é exibido e ocultado automaticamente em resposta aos comandos do usuário — embora você também possa invocá-lo programaticamente. A amostra na Figura 5 mostra um AppBar completo com botões para adicionar, excluir e atualizar dados.

Você pode escrever código para mostrar, ocultar, habilitar e desabilitar botões do AppBar, conforme a demanda do cenário. 

Como uma tela sensível ao toque é uma cidadã de primeira classe, você deve ter percebido que, quando os elementos da interface do usuário e as caixas de diálogos são exibidas, é possível ocultá-las com facilidade simplesmente tocando ou clicando em qualquer parte da tela que não seja na própria caixa de diálogo. Essa noção de fechar implicitamente a caixa diálogo é chamada “descarte suave” e é o comportamento padrão de caixas de diálogo de mensagens e menus pop-up no Windows 8, pois esse descarte suave é muito mais fácil para o usuário do que ele ter de lidar com botões para fechar.

Assim como com os controles anteriores, o submenu usa o atributo data-­win-control para especificar que ele é realmente um controle WinJS.UI.Flyout. Os filhos do elemento <div> do submenu são renderizados dentro do submenu. Por exemplo, você pode colocar um formulário HTML em um submenu, de forma que o usuário possa preencher um cargo e uma data para um evento futuro, como o código ilustrado na Figura 6, gerando o que você pode ver na Figura 7.  

Figura 6 Um submenu de descarte suave para coletar informações com controles do WinJS

    <!-- HTML  -->
    <div id="eventFlyoutPanel" data-win-control="WinJS.UI.Flyout">
      <table width="100%" height="100%">    
        <tr><td>Event Title:</td><td><input type="text"
     id="eventTitle"/></td></tr>
        <tr><td>Event Date:</td><td id="eventDate"
           data-win-control="WinJS.UI.DatePicker"></td></tr>        
        <tr><td> </td><td align="right">
        <input type="button" id="confirmButton" value="Submit" /></td></tr>
        </table>
    </div>
    // JavaScript
    addButtonClick: function () {
      document.getElementById("eventFlyoutPanel").winControl.show(
      "addButton", "top");
    }


Figura 7 Um submenu para coletar informações

Observe que o submenu na Figura 7 é apenas um formulário HTML. Quando o usuário toca ou clica no comando Adicionar do AppBar, o submenu é exibido, conforme direcionado na função addButtonClick na Figura 6. Os submenus são exibidos na tela em relação a outros controles, de forma que, ao chamar o método winControl.show, você transmite o nome do elemento âncora de controle, bem como o local em que ele deve ser colocado, ou seja, próximo à borda superior ou inferior do controle de âncora.

O usuário pode tocar ou clicar em qualquer lugar fora do submenu para que ele seja ocultado, pois ele é um controle de descarte suave. Você perceberá a evidente ausência de caixas de diálogo modais em aplicativos da Windows Store, o que é parte da filosofia de design da Microsoft. Os itens nos círculos de design reprovam as caixas de diálogo por um bom motivo: qualquer coisa que incomode um usuário ou bloqueie sua livre movimentação é considerado um design inadequado.

Outro tipo de submenu é o SettingsFlyout, que é uma grande mudança em relação à maneira como os aplicativos em versões anteriores do Windows gerenciam as preferências do usuário.

Configurações de aplicativo

Os usuários do Windows não são estranhos para as opções de menu Ferramentas | Opções ou Ajuda | Sobre comuns que abrem caixas de diálogo com um labirinto de configurações. Felizmente, o que substituiu essas caixas de diálogo nos aplicativos da Windows Store é muito mais intuitivo para os usuários. As páginas Configurações e Sobre funcionam como controles de submenu altos e verticais, invocados quando o usuário seleciona o ícone Configurações em Botões do Windows (bit.ly/146cniM).

As configurações funcionam de maneira consistente entre aplicativos da Windows Store. Quando o usuário invoca o botão Configurações, o mesmo SettingsFlyout é exibido na lateral direita, independentemente do aplicativo em execução. Os links para a política de privacidade, as preferências do usuário, a ajuda, entre outros, residem no SettingsFlyout. A criação de links para as suas páginas de privacidade ou de opções exige apenas algumas linhas de código no evento app.onactivated, normalmente encontrado em /js/default.js:

    // In default.js, app.onactivated
    
    WinJS.Application.onsettings = function (e) {
    
      e.detail.applicationcommands =
       { "privacypolicy": { title: "Privacy Policy",
     href: "privacy.html" } };
    
        WinJS.UI.SettingsFlyout.populateSettings(e);
    
    };

Após o usuário tocar ou clicar em um dos links de Configurações, o submenu correspondente é exibido. A Figura 8 apresenta o HTML para um SettingsFlyout que contém informações de política de privacidade (uma política de privacidade clara e concisa é uma exigência para a publicação na Windows Store).

Figura 8 O HTML para um submenu Configurações que contém informações de política de privacidade

<div id="settingsFlyout" 
  data-win-control="WinJS.UI.SettingsFlyout"
  data-win-options="{settingsCommandId:'privacypolicy', width:'narrow'}">
  <div class="win-header" style="background-color:#312e2e">
    <button type="button" onclick="WinJS.UI.SettingsFlyout.show()"
       class="win-backbutton"></button>
    <div class="win-label">Privacy Policy</div>
  </div>
  <div class="win-content">
    <div class="win-settings-section">
      <p>This application does not collect any personal information.</p>
      <p>Internet access is only used to retrieve data from the web,<div id="settingsFlyout" 
  data-win-control="WinJS.UI.SettingsFlyout"
  data-win-options="{settingsCommandId:'privacypolicy', width:'narrow'}">
  <div class="win-header" style="background-color:#312e2e">
    <button type="button" onclick="WinJS.UI.SettingsFlyout.show()"
       class="win-backbutton"></button>
    <div class="win-label">Privacy Policy</div>
  </div>
  <div class="win-content">
    <div class="win-settings-section">
      <p>This application does not collect any personal information.</p>
      <p>Internet access is only used to retrieve data from the web,
         or to allow you to contact the developer:</p>
          <p>
            <a href="mailto:rachel@rachelappel.com">Email Rachel Appel </a>
 <br />
            <a href="http://rachelappel.com/privacy-policy"
             target="_blank">View privacy statement online</a>
          </p>
      </div>
  </div>
</div>

         or to allow you to contact the developer:</p>
          <p>
            <a href="mailto:rachel@rachelappel.com">Email Rachel Appel </a>
 <br />
            <a href="http://rachelappel.com/privacy-policy"
             target="_blank">View privacy statement online</a>
          </p>
      </div>
  </div>
</div>

Não se esqueça de nomear o arquivo de configurações da política de privacidade da mesma maneira que o argumento href usado para registrar o submenu (consulte a Figura 8).

As políticas de privacidade não são as únicas coisas que você pode colocar em Configurações. SettingsFlyouts podem conter qualquer HTML válido e, frequentemente, hospedam ToggleSwitches, CheckBoxes e DropDowns, e funcionam exatamente da mesma maneira que as caixas de diálogo Ferramentas | Opções fazem agora. Entretanto, conforme mencionado, os SettingsFlyouts são controles de descarte suave e, por isso, um simples toque em qualquer lugar os faz desaparecer, bastante diferente das caixas de diálogo modais. Outro paradigma simples, porém novo, no desenvolvimento de aplicativos da Windows Store é o controle SemanticZoom, um auxiliar de navegação útil.

Zoom Semântico

Alguns aplicativos são de uso intensivo de dados. A navegação nesses aplicativos pode ser bastante difícil, especialmente quando eles manipulam muitos dados. É aí que o zoom semântico entra em ação. O zoom semântico permite que você expresse dois modos de visualização de dados: ampliado e reduzido. O modo ampliado, o padrão, mostra todos os dados possíveis, e o usuário deve usar o movimento panorâmico ou rolar por eles. O modo reduzido geralmente forma uma representação agregada dos dados, facilitando para o usuário navegar até uma área de dados e, em seguida, ampliar um item de dados específico.

Um SemanticZoom é um conjunto de três controles: o controle de host e os dois controles de zoom, conforme exibido na Figura 9. Os controles filho devem implementar o IZoomable para participar do zoom semântico; dessa maneira, para os aplicativos do WinJS, o ListView é o único que funcionará.

Figura 9 Código do controle SemanticZoom

    <div id="semanticZoomDiv" data-win-control="WinJS.UI.SemanticZoom">            
      <!-- The zoomed-in view. -->   
      <div id="zoomedInListView"
        data-win-control="WinJS.UI.ListView"
        data-win-options="{ itemDataSource:
          myData.groupedItemsList.dataSource,
         itemTemplate: select('#mediumListIconTextTemplate'),
         groupHeaderTemplate: select('#headerTemplate'),
         groupDataSource: myData.groupedItemsList.groups.dataSource,
         selectionMode: 'none',
         tapBehavior: 'none',
         swipeBehavior: 'none' }">  </div>
      <!-- The zoomed-out view. -->
      <div id="zoomedOutListView"
        data-win-control="WinJS.UI.ListView"
        data-win-options="{ itemDataSource:
         myData.groupedItemsList.groups.dataSource, itemTemplate:
         select('#semanticZoomTemplate'), selectionMode: 'none',
         tapBehavior: 'invoke', swipeBehavior: 'none' }">
      </div>
    </div>

Como você pode verificar, o zoom semântico é apenas a inversão entre dois ListViews, o que o torna um excelente modo de transporte alternativo para os usuários — e fácil de implementar para os desenvolvedores.

Mais controles

Existem mais controles — como Progress bar, FlipView, pop-up menus, MessageDialog e Ratings — que fazem parte da nova experiência do Windows, mas eu não tenho espaço para discutir todos eles aqui. Os padrões abertos, como HTML5 e ECMAScript 5 (ES5), são a base para tudo do WinJS e, por isso, tudo, desde recursos básicos da Web até âncoras e entradas para áudio e vídeo em HTML5, funciona perfeitamente como parte da plataforma de desenvolvimento de aplicativos da Windows Store.

Rachel Appel é consultora, autora, mentora e antiga funcionária da Microsoft com mais de 20 anos de experiência no setor de TI. Ela dá palestras em importantes congressos do setor, como o Visual Studio Live!, o DevConnections, o MIX e muitos outros. Sua experiência está ligada a soluções de desenvolvimento que alinham negócios e tecnologia com foco na pilha de desenvolvimento da Microsoft e em Web aberta. Para obter mais informações sobre a Appel, visite seu site em rachelappel.com.

 Agradecemos ao seguinte especialista técnico pela revisão deste artigo: Keith Boyd (Microsoft)