資訊卡瀏覽

大部分的卡片式外掛程式都使用多張資訊卡建構,分別代表外掛程式介面的不同「頁面」。為提供有效的使用者體驗,建議您透過外掛程式,以簡單自然的方式瀏覽資訊卡。

原本在 Gmail 外掛程式中,使用者切換 UI 資訊卡時,是透過將資訊卡推送至或從單一卡片堆疊,以及 Gmail 顯示的堆疊頂端資訊卡進行轉換。

首頁資訊卡導覽

Google Workspace 外掛程式推出首頁和非內容卡。為配合內容卡和非內容卡,Google Workspace 外掛程式為每種資訊卡都有內部資訊卡堆疊。在主機中開啟外掛程式時,對應的 homepageTrigger 會觸發,在堆疊中建立第一個首頁資訊卡 (下圖中的深藍色「首頁」資訊卡)。如未定義 homepageTrigger,系統會建立、顯示預設資訊卡,然後推送至非關聯堆疊。第一張資訊卡是卡片。

您的外掛程式可以建立其他非內容資訊卡,並在使用者瀏覽外掛程式時,將這些資訊卡推送至堆疊 (圖中為藍色的「推送的卡片」)。外掛程式 UI 會在堆疊中顯示頂端資訊卡,因此將新資訊卡推送至堆疊會改變顯示畫面,從堆疊中彈出資訊卡則會將顯示畫面傳回至先前的資訊卡。

如果外掛程式已定義內容相關觸發條件,當使用者進入該結構定義時,觸發條件就會觸發。觸發條件函式會建構內容相關資訊卡,但系統會根據新卡片的 DisplayStyle 更新 UI 顯示內容:

  • 如果 DisplayStyleREPLACE (預設值),內容相關資訊卡 (圖表中的深橘色「內容」資訊卡) 會取代目前顯示的資訊卡。這麼做可有效在非內容資訊卡堆疊上方啟動新的內容卡堆疊,且此內容資訊卡是內容堆疊的「根」資訊卡。
  • 如果 DisplayStylePEEK,UI 會改為建立顯示在外掛程式側欄底部的迅速瀏覽標頭,重疊在目前的資訊卡上。預覽標頭會顯示新資訊卡的標題,並提供使用者按鈕控制項,讓使用者決定是否要查看新的資訊卡。如果使用者點選「View」按鈕,資訊卡會取代目前的資訊卡 (如上所述,用 REPLACE)。

您可以建立其他內容卡,並將其推送至堆疊中 (圖中黃色的「推送的卡片」)。更新資訊卡堆疊後,外掛程式 UI 會變更為顯示最頂端的資訊卡。當使用者離開內容,系統會移除堆疊上的內容資訊卡,並將更新到最頂層的非內容資訊卡或首頁。

如果使用者輸入的內容並未定義內容相關觸發條件,則系統不會建立新資訊卡,且仍會顯示目前的資訊卡。

以下所述的 Navigation 動作只會對相同情境的資訊卡執行操作;舉例來說,來自內容相關資訊卡的 popToRoot() 只會彈出所有其他內容相關資訊卡,且不會影響首頁資訊卡。

相反地,系統一律會使用 按鈕,讓使用者從內容卡前往非內容資訊卡。

您可以從資訊卡堆疊中新增或移除資訊卡,藉此建立資訊卡之間的轉場效果。Navigation 類別提供從堆疊推送及彈出資訊卡的功能。如要打造有效的卡片導覽功能,請將小工具設為使用導覽動作。您可以同時推送或彈出多張資訊卡,但無法在外掛程式啟動時移除首次推送至堆疊上的初始首頁資訊卡。

如要前往新資訊卡以回應使用者與小工具的互動,請按照下列步驟操作:

  1. 建立 Action 物件,並將其與您定義的回呼函式建立關聯。
  2. 呼叫小工具適當的小工具處理常式函式,以設定該小工具的 Action
  3. 實作進行導覽的回呼函式。這個函式會將動作事件物件做為引數指定,且必須執行下列操作:
    1. 建立 Navigation 物件以定義資訊卡變更。單一 Navigation 物件可包含多個導覽步驟,這些步驟會按照新增到物件的順序執行。
    2. 使用 ActionResponseBuilder 類別和 Navigation 物件建構 ActionResponse 物件。
    3. 傳回已建構的 ActionResponse

建構導覽控制項時,您可以使用下列 Navigation 物件函式:

函式 說明
Navigation.pushCard(Card) 將資訊卡推送至目前的堆疊。這需要先完全建構卡片。
Navigation.popCard() 從分疊頂端移除一張資訊卡。相當於點選外掛程式標題列中的返回箭頭。這項操作不會移除根卡片。
Navigation.popToRoot() 從堆疊中移除所有資訊卡 (根資訊卡除外)。基本上重設卡片堆疊。
Navigation.popToNamedCard(String) 從堆疊中彈出資訊卡,直到到達包含指定名稱或堆疊根資訊卡的資訊卡。您可以使用 CardBuilder.setName(String) 函式指派資訊卡名稱。
Navigation.updateCard(Card) 直接取代目前的卡片,讓卡片在 UI 中顯示。

如果使用者互動或事件應導致在相同情境下重新轉譯資訊卡,請使用 Navigation.pushCard()Navigation.popCard()Navigation.updateCard() 方法取代現有資訊卡。如果使用者的互動或事件會導致資訊卡在不同的情境下重新轉譯,請使用 ActionResponseBuilder.setStateChanged() 在這些情境中強制重新執行外掛程式。

以下是導覽範例:

  • 如果互動或事件會變更目前資訊卡的狀態 (例如將任務新增至工作清單),請使用 updateCard()
  • 如果互動或事件提供更多詳細資料,或提示使用者進行進一步動作 (例如:按一下項目標題查看更多詳細資料,或按下按鈕建立新的日曆活動),請使用 pushCard() 顯示新頁面,同時讓使用者使用返回按鈕離開新頁面。
  • 如果互動或事件會更新上一張資訊卡中的狀態 (例如透過詳細資料檢視畫面更新項目標題),請使用 popCard()popCard()pushCard(previous)pushCard(current) 等形式更新先前的資訊卡和目前的資訊卡。

正在重新整理資訊卡

Google Workspace 外掛程式會重新執行資訊清單中註冊的 Apps Script 觸發條件函式,讓使用者能重新整理卡片。使用者透過外掛程式選單項目觸發這個重新整理:

Google Workspace 外掛程式側欄

這個動作會自動新增至由 homepageTriggercontextualTrigger 觸發函式產生的資訊卡,如外掛程式的資訊清單檔案 (結構定義和非結構定義資訊卡堆疊的「根」) 所指定。

退回多張卡片

外掛程式資訊卡範例

首頁或內容相關觸發條件函式可用來建構及傳回單一 Card 物件,或應用程式 UI 顯示的 Card 物件陣列。

如果只有一張資訊卡,系統會將資訊卡新增至非關聯或內容堆疊做為根資訊卡,並在主機應用程式 UI 中顯示。

如果傳回的陣列包含多個建構的 Card 物件,主機應用程式會改為顯示新的資訊卡,其中包含每張卡片標頭的清單。使用者點選任一標頭時,UI 就會顯示對應的資訊卡。

使用者選取清單中的資訊卡時,卡片會推送至目前的堆疊,主機應用程式也會顯示該卡片。 按鈕會將使用者導向資訊卡標頭清單。

如果外掛程式不需要在您建立的資訊卡之間轉換,這種「扁平式」卡片排列方式就很適合。但在大多數情況下,建議您直接定義資訊卡轉換,並讓首頁和情境觸發函式傳回單一卡片物件。

範例

以下範例說明如何建構多張含有導覽按鈕的資訊卡,且這些資訊卡可在資訊卡之間自由切換。您可以將這些資訊卡新增至特定情境中或外部,藉此將 createNavigationCard() 傳回的資訊卡推送至情境式或非內容堆疊。

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