Большинство надстроек на основе карт создаются с использованием нескольких карточек , которые представляют разные «страницы» интерфейса надстройки. Чтобы обеспечить эффективное взаимодействие с пользователем, вы должны использовать простую и естественную навигацию между карточками в своем дополнении.
Первоначально в надстройках Gmail переходы между различными карточками пользовательского интерфейса обрабатывались путем нажатия и извлечения карточек из одной стопки карточек, при этом Gmail отображает верхнюю карточку стопки.
Дополнения Google Workspace представляют главные страницы и неконтекстные карточки. Для размещения контекстных и неконтекстных карточек в надстройках Google Workspace предусмотрена внутренняя стопка карточек для каждой из них. Когда надстройка открывается на узле, срабатывает соответствующий homepageTrigger
, чтобы создать первую карточку домашней страницы в стеке (темно-синяя карточка «домашняя страница» на диаграмме ниже). Если homepageTrigger
не определен, карточка по умолчанию создается, отображается и помещается в неконтекстный стек. Эта первая карта является корневой картой.
Ваше дополнение может создавать дополнительные неконтекстные карточки и помещать их в стек (синие «вталкиваемые карточки» на диаграмме) по мере того, как пользователь перемещается по вашему дополнению. Пользовательский интерфейс надстройки отображает верхнюю карту в стопке, поэтому добавление новых карт в стопку изменяет отображение, а удаление карт из стопки возвращает отображение к предыдущим карточкам.
Если в вашей надстройке есть определенный контекстный триггер , когда пользователь входит в этот контекст, срабатывает триггер. Функция триггера создает контекстную карточку, но отображение пользовательского интерфейса обновляется на основе DisplayStyle
новой карточки:
- Если
DisplayStyle
имеет значениеREPLACE
(по умолчанию), контекстная карточка (темно-оранжевая «контекстная» карточка на диаграмме) заменяет текущую отображаемую карточку. Это фактически запускает новый стек контекстных карточек поверх стека неконтекстных карточек, и эта контекстная карточка является корневой карточкой контекстуального стека. - Если
DisplayStyle
имеет значениеPEEK
, вместо этого пользовательский интерфейс создает заголовок для просмотра, который отображается в нижней части боковой панели надстройки, перекрывая текущую карточку. Заголовок просмотра показывает заголовок новой карты и предоставляет пользователю элементы управления кнопками, которые позволяют им решать, просматривать ли новую карту или нет. Если они нажмут кнопку View , карта заменит текущую карту (как описано выше сREPLACE
).
Вы можете создавать дополнительные контекстные карты и помещать их в стек (желтые «выталкиваемые карты» на диаграмме). Обновление стопки карт изменяет пользовательский интерфейс надстройки для отображения самой верхней карты. Если пользователь покидает контекст, контекстные карточки в стеке удаляются, а отображение обновляется до самой верхней неконтекстной карточки или домашней страницы.
Если пользователь входит в контекст, для которого ваше дополнение не определяет контекстный триггер, новая карточка не создается, а текущая карточка остается отображаемой.
Действия Navigation
, описанные ниже, действуют только на карточки из одного и того же контекста; например, popToRoot()
внутри контекстной карточки только извлекает все другие контекстные карточки и не влияет на карточки домашней страницы.
Напротив, кнопка
всегда доступна для пользователя, чтобы перейти от ваших контекстных карточек к вашим неконтекстным карточкам.Способы навигации
Вы можете создавать переходы между картами, добавляя или удаляя карты из стопки карт. Класс Navigation
предоставляет функции для выталкивания и извлечения карт из стеков. Чтобы создать эффективную карточную навигацию, вы настраиваете свои виджеты для использования действий навигации. Вы можете вставлять или извлекать несколько карточек одновременно, но вы не можете удалить исходную карточку домашней страницы, которая первой помещается в стек при запуске надстройки.
Чтобы перейти к новой карточке в ответ на взаимодействие пользователя с виджетом, выполните следующие действия:
- Создайте объект
Action
и свяжите его с определяемой вами функцией обратного вызова . - Вызовите соответствующую функцию обработчика виджета , чтобы задать
Action
для этого виджета. - Реализуйте функцию обратного вызова, которая осуществляет навигацию. Эта функция получает в качестве аргумента объект события действия и должна выполнять следующие действия:
- Создайте объект
Navigation
, чтобы определить изменение карты. Один объектNavigation
может содержать несколько шагов навигации, которые выполняются в том порядке, в котором они добавляются к объекту. - Создайте объект
ActionResponse
, используя классActionResponseBuilder
и объектNavigation
. - Верните построенный
ActionResponse
.
- Создайте объект
При создании элементов управления навигацией вы используете следующие функции объекта Navigation
:
Функция | Описание |
---|---|
Navigation.pushCard(Card) | Помещает карту в текущий стек. Для этого необходимо сначала полностью построить карту. |
Navigation.popCard() | Удаляет одну карту с верха стопки. Эквивалент щелчка по стрелке назад в строке заголовка надстройки. Это не удаляет корневые карты. |
Navigation.popToRoot() | Удаляет все карты из стопки, кроме корневой карты. По сути сбрасывает этот стек карт. |
Navigation.popToNamedCard(String) | Выталкивает карты из стопки, пока не достигнет карты с заданным именем или корневой карты стопки. Карточкам можно присваивать имена с помощью функции CardBuilder.setName(String) . |
Navigation.updateCard(Card) | Заменяет текущую карту на месте, обновляя ее отображение в пользовательском интерфейсе. |
Лучшая практика навигации
Если взаимодействие с пользователем или событие должно привести к повторному рендерингу карточек в том же контексте, используйте методы Navigation.pushCard()
, Navigation.popCard()
и Navigation.updateCard()
для замены существующих карточек. Если взаимодействие с пользователем или событие должно привести к повторному рендерингу карточек в другом контексте, используйте ActionResponseBuilder.setStateChanged()
для принудительного повторного выполнения надстройки в этих контекстах.
Ниже приведены примеры навигации:
- Если взаимодействие или событие изменяет состояние текущей карты (например, добавление задачи в список задач), используйте
updateCard()
. - Если взаимодействие или событие предоставляет дополнительную информацию или предлагает пользователю дальнейшие действия (например, щелкнуть заголовок элемента, чтобы просмотреть дополнительные сведения, или нажать кнопку, чтобы создать новое событие календаря), используйте
pushCard()
, чтобы отобразить новую страницу во время позволяя пользователю выйти с новой страницы с помощью кнопки «Назад». - Если взаимодействие или событие обновляет состояние в предыдущей карточке (например, обновление заголовка элемента из подробного представления), используйте что-то вроде
popCard()
,popCard()
,pushCard(previous)
иpushCard(current)
для обновления предыдущего карта и текущая карта.
Обновление карт
Дополнения Google Workspace дают пользователям возможность обновить вашу карточку, повторно запустив триггерную функцию скрипта приложений, зарегистрированную в вашем манифесте. Пользователи запускают это обновление через дополнительный пункт меню:
Это действие автоматически добавляется к карточкам, сгенерированным триггерными функциями homepageTrigger
или contextualTrigger
, как указано в файле манифеста надстройки («корни» контекстных и неконтекстных стеков карточек).
Возврат нескольких карт
Домашняя страница или контекстные триггерные функции используются для создания и возврата либо одного объекта Card
, либо массива объектов Card
, которые отображаются в пользовательском интерфейсе приложения.
Если имеется только одна карта, она добавляется в неконтекстный или контекстный стек, поскольку корневая карта и пользовательский интерфейс хост-приложения отображают ее.
Если возвращенный массив включает в себя более одного встроенного объекта Card
, ведущее приложение вместо этого отображает новую карточку, содержащую список заголовков каждой карточки. Когда пользователь щелкает любой из этих заголовков, пользовательский интерфейс отображает соответствующую карточку.
Когда пользователь выбирает карту из списка, эта карта помещается в текущий стек, и хост-приложение отображает ее. Кнопка
возвращает пользователя к списку заголовков карточек.Это «плоское» расположение карт может хорошо работать, если вашему дополнению не нужны переходы между карточками, которые вы создаете. Однако в большинстве случаев лучше напрямую определять переходы карточек, чтобы главная страница и контекстные триггерные функции возвращали один объект карточки.
Пример
Вот пример, показывающий, как создать несколько карточек с кнопками навигации, которые перемещаются между ними. Эти карты могут быть добавлены либо в контекстный, либо в неконтекстный стек путем помещения карты, возвращаемой функцией 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();
}