大多數的卡片型外掛程式都是使用多個資訊卡建構,代表外掛程式介面的不同「頁面」。如要提供有效的使用者體驗,建議您以簡單自然的方式在外掛程式中切換資訊卡。
一開始在 Gmail 外掛程式中,不同 UI 資訊卡之間的轉換,是透過單一資訊卡堆疊推送及彈出,並由 Gmail 顯示堆疊最頂端的資訊卡。
Google Workspace 外掛程式推出了首頁和非內容資訊卡。為配合內容資訊卡和非內容資訊卡,Google Workspace 外掛程式會為其套用內部資訊卡堆疊。在主機中開啟外掛程式時,對應的 homepageTrigger
會觸發,在堆疊中建立第一個首頁資訊卡 (下圖中的深藍色「首頁」資訊卡)。如未定義 homepageTrigger
,系統會建立、顯示預設卡片,並推送至非內容堆疊上。第一張卡片是根卡。
外掛程式可以建立其他與內容無關的資訊卡,並在使用者瀏覽外掛程式時,將其推送至堆疊 (圖表中的藍色「推送卡片」)。外掛程式 UI 會顯示堆疊中的頂端資訊卡,因此將新資訊卡推送至堆疊會變更顯示畫面,從堆疊中移除資訊卡則會返回之前的資訊卡。
如果您的外掛程式有已定義的內容相關觸發條件,系統就會在使用者輸入該內容時觸發觸發條件。觸發函式會建構內容相關資訊卡,但 UI 顯示會根據新卡片的 DisplayStyle
更新:
- 如果
DisplayStyle
為REPLACE
(預設值),內容資訊卡 (圖表中的深橘色「內容」資訊卡) 會取代目前顯示的資訊卡。這樣做能有效地在非內容資訊卡堆疊之上啟動新的關聯資訊卡堆疊,而內容相關資訊卡是結構定義堆疊的「根」資訊卡。 - 如果
DisplayStyle
是PEEK
,UI 就會改為在外掛程式側欄底部建立短暫顯示標頭,並與目前的資訊卡重疊。提示標頭會顯示新資訊卡的標題,並提供使用者按鈕控制項,讓使用者決定是否要檢視新卡片。如果他們按一下「View」按鈕,資訊卡就會取代目前的資訊卡 (如上所述,替換為REPLACE
)。
您可以建立其他內容資訊卡,並將其推送至堆疊 (圖表中為黃色「推送的卡片」)。更新資訊卡堆疊會變更外掛程式 UI,以顯示最頂端的資訊卡。如果使用者離開結構定義,系統就會移除堆疊上的內容資訊卡,並顯示更新到內容最不具關聯的資訊卡或首頁。
如果使用者輸入的結構定義未定義內容觸發條件,系統就不會建立新卡片,且目前的資訊卡仍會顯示。
下文所述的 Navigation
動作只會對相同情境的資訊卡執行;舉例來說,來自內容資訊卡的 popToRoot()
只會彈出所有其他內容資訊卡,也不會影響首頁資訊卡。
相對地,使用者一律可以使用
按鈕,從內容資訊卡前往非內容資訊卡。導覽方法
您可以在資訊卡堆疊中新增或移除資訊卡,藉此在資訊卡之間建立轉場效果。Navigation
類別提供用於從堆疊推送和彈出資訊卡的功能。如要建構有效的卡片導覽功能,請將小工具設為使用導覽動作。您可以同時推送或彈出多張資訊卡,但無法移除在外掛程式啟動時首次推送至堆疊上的初始首頁資訊卡。
如要前往新資訊卡以回應使用者與小工具互動,請按照下列步驟操作:
- 建立
Action
物件,並將其與您定義的回呼函式建立關聯。 - 呼叫小工具的適當小工具處理常式函式,設定該小工具的
Action
。 - 實作執行導覽的回呼函式。這個函式會將操作事件物件做為引數,且必須執行下列操作:
- 建立
Navigation
物件來定義卡片變更。單一Navigation
物件可包含多個導覽步驟,這些步驟將依新增至物件的順序執行。 - 使用
ActionResponseBuilder
類別和Navigation
物件建構ActionResponse
物件。 - 傳回已經建構的
ActionResponse
。
- 建立
建構導覽控制項時,您必須使用下列 Navigation
物件函式:
函式 | 說明 |
---|---|
Navigation.pushCard(Card) |
將資訊卡推送至目前的堆疊。為此,您必須先建構卡片。 |
Navigation.popCard() |
從堆疊頂端移除一張資訊卡。相當於點選外掛程式標題列中的返回箭頭。這不會移除根卡片。 |
Navigation.popToRoot() |
從堆疊中移除所有卡片,根卡片除外。系統會重設該資訊卡堆疊。 |
Navigation.popToNamedCard(String) |
從堆疊中彈出資訊卡,直到抵達具有指定名稱或堆疊根資訊卡的資訊卡為止。您可以使用 CardBuilder.setName(String) 函式為資訊卡指派名稱。 |
Navigation.updateCard(Card) |
進行直接取代現有卡片,重新整理使用者介面中顯示的卡片。 |
Navigation 最佳做法
如果使用者的互動或事件應以相同的情境重新轉譯資訊卡,請使用 Navigation.pushCard()
、Navigation.popCard()
和 Navigation.updateCard()
方法取代現有的資訊卡。如果使用者的互動或事件應在不同情境下重新轉譯資訊卡,請在這些情況下使用 ActionResponseBuilder.setStateChanged()
強制重新執行外掛程式。
以下是導覽範例:
- 如果互動或事件會變更目前資訊卡的狀態 (例如將任務新增至工作清單),請使用
updateCard()
。 - 如果互動或事件提供更多詳細資料,或提示使用者執行後續動作 (例如按一下項目標題以查看詳細資料,或按下按鈕建立新的日曆活動),請使用
pushCard()
顯示新頁面,並讓使用者使用返回按鈕離開新頁面。 - 如果前一張資訊卡的互動或事件更新了狀態 (例如,使用詳細資料檢視畫面更新項目標題),請使用
popCard()
、popCard()
、pushCard(previous)
和pushCard(current)
等函式來更新先前的卡片和目前的卡片。
正在重新整理卡片
Google Workspace 外掛程式可讓使用者重新執行資訊清單中註冊的 Apps Script 觸發條件函式,藉此重新整理資訊卡。使用者會透過外掛程式選單項目觸發這個重新整理程序:
此動作會自動新增至 homepageTrigger
或 contextualTrigger
觸發函式產生的資訊卡中,如同外掛程式的資訊清單檔案 (內容相關資訊卡和非內容資訊卡堆疊的「根」項目)。
傳回多張卡片
首頁或內容相關觸發條件函式可用來建構及傳回應用程式 UI 顯示的單一 Card
物件或 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();
}