Navigazione schede

La maggior parte dei componenti aggiuntivi basati su schede sono creati utilizzando più schede che rappresentano diverse "pagine" dell'interfaccia del componente aggiuntivo. Per un'esperienza utente efficace, devi utilizzare una navigazione semplice e naturale tra le schede del componente aggiuntivo.

Originariamente negli add-on di Gmail, le transizioni tra le diverse schede della UI vengono gestite spostando le schede in una singola pila e viceversa, con la scheda superiore della pila visualizzata da Gmail.

Navigazione nelle schede della home page

I componenti aggiuntivi di Google Workspace introducono home page e schede non contestuali. Per ospitare schede contestuali e non contestuali, i componenti aggiuntivi di Google Workspace hanno uno stack di schede interno per ciascuna. Quando un componente aggiuntivo viene aperto in un host, viene attivato il corrispondente homepageTrigger per creare la prima scheda della home page nello stack (la scheda "home page" blu scuro nel diagramma seguente). Se non viene definito un homepageTrigger, viene creata, visualizzata e inserita nello stack non contestuale una scheda predefinita. La prima scheda è una scheda radice.

Il componente aggiuntivo può creare schede non contestuali aggiuntive e inserirle nello stack (le "schede inserite" blu nel diagramma) man mano che l'utente naviga nel componente aggiuntivo. L'interfaccia utente del componente aggiuntivo mostra la prima scheda dello stack, quindi l'inserimento di nuove schede nello stack modifica la visualizzazione e l'eliminazione di schede dallo stack ripristina la visualizzazione delle schede precedenti.

Se il componente aggiuntivo ha un trigger contestuale definito, quando l'utente inserisce quel contesto, il trigger viene attivato. La funzione di trigger crea la scheda contestuale, ma la visualizzazione dell'interfaccia utente viene aggiornata in base al DisplayStyle della nuova scheda:

  • Se DisplayStyle è REPLACE (impostazione predefinita), la scheda contestuale (la scheda "contestuale" arancione scuro nel diagramma) sostituisce la scheda attualmente visualizzata. In questo modo, viene avviata una nuova pila di schede contestuali sopra la pila di schede non contestuali e questa scheda contestuale è la scheda radice della pila contestuale.
  • Se DisplayStyle è PEEK, la UI crea invece un'intestazione che appare nella parte inferiore della barra laterale dei componenti aggiuntivi, sovrapponendosi alla scheda corrente. L'intestazione dell'anteprima mostra il titolo della nuova scheda e fornisce i controlli dei pulsanti utente che consentono di decidere se visualizzare o meno la nuova scheda. Se fa clic sul pulsante Visualizza, la scheda sostituisce quella attuale (come descritto sopra con REPLACE).

Puoi creare schede contestuali aggiuntive e trascinarle nello stack (le "schede inviate" gialle nel diagramma). L'aggiornamento della pila di schede modifica la UI del componente aggiuntivo per visualizzare la scheda in primo piano. Se l'utente esce da un contesto, le schede contestuali dello stack vengono rimosse e la visualizzazione viene aggiornata alla scheda non contestuale più in alto o alla home page.

Se l'utente inserisce un contesto per cui il componente aggiuntivo non definisce un trigger contestuale, non viene creata una nuova scheda e viene visualizzata la scheda corrente.

Le azioni Navigation descritte di seguito agiscono solo sulle schede dello stesso contesto. Ad esempio, popToRoot() all'interno di una scheda contestuale apre solo tutte le altre schede contestuali e non influisce sulle schede della home page.

Al contrario, il pulsante è sempre disponibile per l'utente per passare dalle schede contestuali a quelle non contestuali.

Puoi creare transizioni tra le schede aggiungendo o rimuovendo schede dagli stack di schede. La classe Navigation fornisce funzioni per inserire ed estrarre carte dagli stack. Per creare una navigazione efficace tra le schede, configura i widget in modo che utilizzino le azioni di navigazione. Puoi spostare più schede contemporaneamente, ma non puoi rimuovere la scheda della home page iniziale che viene inserita per prima nella pila all'avvio del componente aggiuntivo.

Per passare a una nuova scheda in risposta all'interazione di un utente con un widget, segui questi passaggi:

  1. Crea un oggetto Action e associalo a una funzione di callback che definisci.
  2. Chiama la funzione di gestione dei widget appropriata del widget per impostare Action sul widget.
  3. Implementa la funzione di callback che esegue la navigazione. Questa funzione riceve un oggetto evento azione come argomento e deve svolgere le seguenti operazioni:
    1. Crea un oggetto Navigation per definire la modifica della carta. Un singolo oggetto Navigation può contenere più passaggi di navigazione, che vengono eseguiti nell'ordine in cui vengono aggiunti all'oggetto.
    2. Crea un oggetto ActionResponse utilizzando la classe ActionResponseBuilder e l'oggetto Navigation.
    3. Restituisci il dispositivo ActionResponse.

Quando crei i controlli di navigazione, utilizzi le seguenti funzioni dell'oggetto Navigation:

Funzione Descrizione
Navigation.pushCard(Card) Sposta una carta nella pila corrente. Per farlo, devi prima creare completamente la scheda.
Navigation.popCard() Rimuove una carta dalla parte superiore del mazzo. Equivalente a fare clic sulla freccia indietro nella riga di intestazione del componente aggiuntivo. Le carte principali non vengono rimosse.
Navigation.popToRoot() Rimuove tutte le schede dallo stack, tranne la scheda principale. Reimposta essenzialmente la pila di carte.
Navigation.popToNamedCard(String) Estrae le carte dalla pila fino a raggiungere una carta con il nome specificato o la carta principale della pila. Puoi assegnare nomi alle carte utilizzando la funzione CardBuilder.setName(String).
Navigation.updateCard(Card) Esegue una sostituzione sul posto della carta attuale, aggiornandone la visualizzazione nell'UI.

Se un'interazione o un evento utente deve comportare il rendering di nuovo delle schede nello stesso contesto, utilizza i metodi Navigation.pushCard(), Navigation.popCard() e Navigation.updateCard() per sostituire le schede esistenti. Se un'interazione o un evento utente deve comportare il rendering delle schede in un contesto diverso, utilizza ActionResponseBuilder.setStateChanged() per forzare la riesecuzione del componente aggiuntivo in questi contesti.

Di seguito sono riportati alcuni esempi di navigazione:

  • Se un'interazione o un evento cambia lo stato della scheda corrente (ad esempio, l'aggiunta di un'attività a un elenco di attività), utilizza updateCard().
  • Se un'interazione o un evento fornisce ulteriori dettagli o chiede all'utente un'ulteriore azione (ad esempio, fare clic sul titolo di un elemento per visualizzare ulteriori dettagli o premere un pulsante per creare un nuovo evento di Calendar), utilizza pushCard() per mostrare la nuova pagina consentendo all'utente di uscire dalla nuova pagina utilizzando il pulsante Indietro.
  • Se un'interazione o un evento aggiorna lo stato in una scheda precedente (ad esempio, l'aggiornamento del titolo di un elemento dalla visualizzazione dettagli), utilizza elementi come popCard(), popCard(), pushCard(previous), e pushCard(current) per aggiornare la scheda precedente e quella attuale.

Aggiornamento delle schede

I componenti aggiuntivi di Google Workspace consentono agli utenti di aggiornare la scheda eseguendo nuovamente la funzione di attivazione di Apps Script registrata nel manifest. Gli utenti attivano questo aggiornamento tramite una voce di menu del componente aggiuntivo:

Barra laterale del componente aggiuntivo di Google Workspace

Questa azione viene aggiunta automaticamente alle schede generate dalle funzioni di attivazione homepageTrigger o contextualTrigger, come specificato nel file manifest del componente aggiuntivo (le "radici" degli stack di schede contestuali e non contestuali).

Restituzione di più carte

Scheda componente aggiuntivo di esempio

Le funzioni di attivazione contestuale o della home page vengono utilizzate per creare e restituire un singolo oggetto Card o un array di oggetti Card visualizzati dall'interfaccia utente dell'applicazione.

Se è presente una sola scheda, questa viene aggiunta allo stack non contestuale o contestuale come scheda principale e viene visualizzata nell'interfaccia utente dell'applicazione host.

Se l'array restituito include più di un oggetto Card, l'applicazione host visualizza invece una nuova scheda, che contiene un elenco dell'intestazione di ogni scheda. Quando l'utente fa clic su una di queste intestazioni, l'interfaccia utente mostra la scheda corrispondente.

Quando l'utente seleziona una carta dall'elenco, questa viene inserita nella pila corrente e l'applicazione host la visualizza. Il pulsante riporta l'utente all'elenco delle intestazioni delle schede.

Questa disposizione "piatta" delle schede può essere utile se il componente aggiuntivo non richiede transizioni tra le schede che crei. Nella maggior parte dei casi, tuttavia, è consigliabile definire direttamente le transizioni delle schede e fare in modo che le funzioni di attivazione contestuale e della home page restituiscano un singolo oggetto scheda.

Esempio

Ecco un esempio che mostra come creare diverse schede con pulsanti di navigazione che consentono di passare da una all'altra. Queste schede possono essere aggiunte allo stack contestuale o non contestuale inserendo la scheda restituita da createNavigationCard() all'interno o all'esterno di un contesto specifico.

  /**
   *  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();
  }