Navegação no card

A maioria dos complementos baseados em cards é criada usando vários cards que representam diferentes "páginas" da interface do complemento. Para ter uma experiência do usuário eficaz, use uma navegação simples e natural entre os cards no seu complemento.

Originalmente nos complementos do Gmail, as transições entre diferentes cards da IU são processadas empurrando e mostrando cartões de e para uma única pilha de cartões, com o card superior da pilha exibido pelo Gmail.

Navegação no card da página inicial

Os complementos do Google Workspace introduzem páginas iniciais e cards não contextuais. Para acomodar cards contextuais e não contextuais, os complementos do Google Workspace têm uma pilha de cards interna para cada um. Quando um complemento é aberto em um host, o homepageTrigger correspondente é acionado para criar o primeiro cartão de página inicial na pilha (o cartão "página inicial" azul escuro no diagrama abaixo). Se um homepageTrigger não for definido, um card padrão será criado, exibido e enviado para a pilha não contextual. O primeiro cartão é root.

Seu complemento pode criar outros cards não contextuais e os enviar para a pilha (os "cartões enviados" em azul no diagrama) à medida que o usuário navega pelo complemento. A IU de complementos mostra o cartão superior na pilha. Enviar novos cards à pilha muda a exibição, e retirar cards da pilha faz com que eles voltem para os cards anteriores.

Se o complemento tiver um acionador contextual definido, quando o usuário inserir esse contexto, o acionador será disparado. A função de gatilho cria o card contextual, mas a exibição da IU é atualizada com base no DisplayStyle do novo card:

  • Se DisplayStyle for REPLACE (o padrão), o card contextual (o card "contextual" alaranjado escuro no diagrama) substituirá o card exibido no momento. Isso inicia efetivamente uma nova pilha de cards contextuais na parte de cima da pilha de cards não contextuais, e esse card é o card raiz da pilha contextual.
  • Se o DisplayStyle for PEEK, a IU vai criar um cabeçalho aberto na parte de baixo da barra lateral do complemento, sobrepondo o cartão atual. O cabeçalho mostra o título do novo card e fornece controles do botão do usuário que permitem que ele decida se vai ver o novo card ou não. Se ele clicar no botão Visualizar, o card vai substituir o cartão atual (conforme descrito acima por REPLACE).

É possível criar outros cartões contextuais e empurrá-los para a pilha (os "cartões enviados" amarelos no diagrama). A atualização da pilha de cartões muda a IU do complemento para exibir o cartão na parte superior. Se o usuário sair de um contexto, os cards contextuais na pilha são removidos e a tela é atualizada para o card ou a página inicial mais não contextuais.

Se o usuário inserir um contexto para o qual seu complemento não define um acionador contextual, nenhum cartão novo será criado, e o cartão atual permanecerá exibido.

As ações Navigation descritas abaixo só funcionam em cards do mesmo contexto. Por exemplo, popToRoot() de um card contextual exibe apenas todos os outros cards contextuais e não afeta os cards da página inicial.

Por outro lado, o botão está sempre disponível para que o usuário navegue dos cards contextuais para os cartões não contextuais.

Você pode criar transições entre cards adicionando ou removendo das pilhas deles. A classe Navigation fornece funções para enviar e retirar cards das pilhas. Para criar uma navegação de card eficaz, configure os widgets para usar ações de navegação. É possível enviar ou remover vários cartões simultaneamente, mas não é possível remover o card inicial da página inicial, que é enviado pela primeira vez para a pilha quando o complemento é iniciado.

Para navegar até um novo card em resposta a uma interação do usuário com um widget, siga estas etapas:

  1. Crie um objeto Action e associe-o a uma função de callback definida.
  2. Chame a função do gerenciador de widgets apropriada para definir o Action nesse widget.
  3. Implemente a função de callback que conduz a navegação. Essa função recebe um objeto de evento de ação como argumento e precisa fazer o seguinte:
    1. Crie um objeto Navigation para definir a mudança do cartão. Um único objeto Navigation pode conter várias etapas de navegação, que são realizadas na ordem em que são adicionadas ao objeto.
    2. Crie um objeto ActionResponse usando a classe ActionResponseBuilder e o objeto Navigation.
    3. Retorne o ActionResponse criado.

Ao criar controles de navegação, use as seguintes funções do objeto Navigation:

Função Descrição
Navigation.pushCard(Card) Empurra um cartão para a pilha atual. Isso requer que o cartão seja criado completamente primeiro.
Navigation.popCard() Remove um card do topo da pilha. Isso equivale a clicar na seta para voltar na linha do cabeçalho do complemento. Isso não remove cartões raiz.
Navigation.popToRoot() Remove todos os cards da pilha, exceto o cartão raiz. Essencialmente, redefine a pilha de cards.
Navigation.popToNamedCard(String) Exibe os cards da pilha até chegar a um card com o nome fornecido ou no cartão raiz da pilha. É possível atribuir nomes aos cards usando a função CardBuilder.setName(String).
Navigation.updateCard(Card) Faz uma substituição no local do cartão atual, atualizando a exibição na IU.

Se uma interação ou evento do usuário resultar em uma nova renderização de cards no mesmo contexto, use os métodos Navigation.pushCard(), Navigation.popCard() e Navigation.updateCard() para substituir os cards existentes. Se uma interação ou evento do usuário resultar na nova renderização de cards em um contexto diferente, use ActionResponseBuilder.setStateChanged() para forçar a nova execução do complemento nesses contextos.

Confira abaixo exemplos de navegação:

  • Se uma interação ou um evento mudar o estado do card atual (por exemplo, adicionar uma tarefa a uma lista), use updateCard().
  • Se uma interação ou um evento fornecer mais detalhes ou solicitar que o usuário realize outras ações (por exemplo, clicar no título de um item para ver mais detalhes ou pressionar um botão para criar um novo evento do Google Agenda), use pushCard() para mostrar a nova página e permitir que o usuário saia dela usando o botão "Voltar".
  • Se uma interação ou um evento atualizar o estado em um card anterior (por exemplo, atualizando o título de um item com a visualização detalhada), use algo como popCard(), popCard(), pushCard(previous) e pushCard(current) para atualizar o card anterior e o atual.

Atualizando cards

Com os complementos do Google Workspace, os usuários podem atualizar seu cartão executando novamente a função de gatilho do Apps Script registrada no seu manifesto. Os usuários acionam essa atualização usando um item de menu de complemento:

Barra lateral de complementos do Google Workspace

Essa ação é adicionada automaticamente a cards gerados por funções de acionamento homepageTrigger ou contextualTrigger, conforme especificado no arquivo de manifesto do complemento (as "raízes" das pilhas de cartões contextuais e não contextuais).

Como devolver vários cartões

Exemplo de cartão de complemento

As funções de início ou de gatilho contextuais são usadas para criar e retornar um único objeto Card ou uma matriz de objetos Card que a IU do aplicativo mostra.

Se houver apenas um cartão, ele será adicionado à pilha não contextual ou contextual como o cartão raiz, e a IU do aplicativo host o exibirá.

Se a matriz retornada incluir mais de um objeto Card criado, o aplicativo host vai mostrar um novo cartão, com uma lista do cabeçalho de cada cartão. Quando o usuário clica em um desses cabeçalhos, a IU mostra o cartão correspondente.

Quando o usuário seleciona um cartão da lista, ele é enviado para a pilha atual e o aplicativo host o exibe. O botão retorna o usuário à lista de cabeçalhos do cartão.

Essa disposição "fixa" pode funcionar bem se o complemento não precisar fazer transições entre os cards criados. No entanto, na maioria dos casos, é recomendável definir diretamente as transições de cards e fazer com que a página inicial e as funções de gatilho contextuais retornem um único objeto de cartão.

Exemplo

Este é um exemplo que mostra como criar vários cards com botões de navegação que se alternam entre eles. Esses cards podem ser adicionados à pilha contextual ou não contextual enviando o cartão retornado por createNavigationCard() dentro ou fora de um contexto específico.

  /**
   *  Create the top-level card, with buttons leading to each of three
   *  'children' cards, as well as buttons to backtrack and return to the
   *  root card of the stack.
   *  @return {Card}
   */
  function createNavigationCard() {
    // Create a button set with actions to navigate to 3 different
    // 'children' cards.
    var buttonSet = CardService.newButtonSet();
    for(var i = 1; i <= 3; i++) {
      buttonSet.addButton(createToCardButton(i));
    }

    // Build the card with all the buttons (two rows)
    var card = CardService.newCardBuilder()
        .setHeader(CardService.newCardHeader().setTitle('Navigation'))
        .addSection(CardService.newCardSection()
            .addWidget(buttonSet)
            .addWidget(buildPreviousAndRootButtonSet()));
    return card.build();
  }

  /**
   *  Create a button that navigates to the specified child card.
   *  @return {TextButton}
   */
  function createToCardButton(id) {
    var action = CardService.newAction()
        .setFunctionName('gotoChildCard')
        .setParameters({'id': id.toString()});
    var button = CardService.newTextButton()
        .setText('Card ' + id)
        .setOnClickAction(action);
    return button;
  }

  /**
   *  Create a ButtonSet with two buttons: one that backtracks to the
   *  last card and another that returns to the original (root) card.
   *  @return {ButtonSet}
   */
  function buildPreviousAndRootButtonSet() {
    var previousButton = CardService.newTextButton()
        .setText('Back')
        .setOnClickAction(CardService.newAction()
            .setFunctionName('gotoPreviousCard'));
    var toRootButton = CardService.newTextButton()
        .setText('To Root')
        .setOnClickAction(CardService.newAction()
            .setFunctionName('gotoRootCard'));

    // Return a new ButtonSet containing these two buttons.
    return CardService.newButtonSet()
        .addButton(previousButton)
        .addButton(toRootButton);
  }

  /**
   *  Create a child card, with buttons leading to each of the other
   *  child cards, and then navigate to it.
   *  @param {Object} e object containing the id of the card to build.
   *  @return {ActionResponse}
   */
  function gotoChildCard(e) {
    var id = parseInt(e.parameters.id);  // Current card ID
    var id2 = (id==3) ? 1 : id + 1;      // 2nd card ID
    var id3 = (id==1) ? 3 : id - 1;      // 3rd card ID
    var title = 'CARD ' + id;

    // Create buttons that go to the other two child cards.
    var buttonSet = CardService.newButtonSet()
      .addButton(createToCardButton(id2))
      .addButton(createToCardButton(id3));

    // Build the child card.
    var card = CardService.newCardBuilder()
        .setHeader(CardService.newCardHeader().setTitle(title))
        .addSection(CardService.newCardSection()
            .addWidget(buttonSet)
            .addWidget(buildPreviousAndRootButtonSet()))
        .build();

    // Create a Navigation object to push the card onto the stack.
    // Return a built ActionResponse that uses the navigation object.
    var nav = CardService.newNavigation().pushCard(card);
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }

  /**
   *  Pop a card from the stack.
   *  @return {ActionResponse}
   */
  function gotoPreviousCard() {
    var nav = CardService.newNavigation().popCard();
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }

  /**
   *  Return to the initial add-on card.
   *  @return {ActionResponse}
   */
  function gotoRootCard() {
    var nav = CardService.newNavigation().popToRoot();
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }