카드 탐색

대부분의 카드 기반 부가기능은 다양한 '페이지'를 나타내는 카드 의 부가기능 인터페이스입니다. 효과적인 사용자 경험을 위해 부가기능에서 카드 간에 간단하고 자연스러운 탐색 기능을 사용해야 합니다.

원래 Gmail 부가기능에서 UI의 여러 카드 간 전환은 단일 카드 스택으로 카드를 푸시하고 팝하는 방식으로 처리되며, Gmail에 표시된 스택의 맨 위 카드입니다.

홈페이지 카드 탐색

Google Workspace 부가기능 홈페이지 및 사용할 수 없습니다. 문맥 카드와 비문맥 카드를 모두 사용하려면 Google Workspace 부가기능에 내부 카드 스택이 있음 있습니다 부가기능이 열릴 때 상응하는 homepageTrigger가 실행되어 첫 번째 스택의 홈페이지 카드 (아래 다이어그램의 진한 파란색 '홈페이지' 카드) homepageTrigger를 정의하지 않으면 기본 카드가 생성되고 표시되고 비컨텍스트 스택으로 푸시됩니다 첫 번째 카드는 루트 카드입니다.

부가기능을 통해 문맥에 맞지 않는 카드를 추가로 만들어 (다이어그램에서 파란색 '푸시된 카드'), 확인할 수 있습니다 부가기능 UI는 스택의 맨 위 카드를 표시하므로 카드를 스택에 넣으면 디스플레이가 변경되고 스택에서 카드를 빼내면 다시 반환됩니다. 이전 카드로 전환할 수 있습니다

부가기능에 정의된 문맥 트리거, 사용자가 트리거가 실행되는 컨텍스트에 들어가면 트리거 함수 컨텍스트 카드가 빌드되지만, UI 디스플레이는 DisplayStyle 드림 변경 후:

  • DisplayStyle REPLACE (기본값), 문맥 카드 (진한 주황색) '상황별' 카드)가 현재 사용 가능한 표시됩니다. 이를 통해 새로운 상황별 카드 스택이 종료되며 이 문맥 카드는 루트입니다. 컨텍스트 스택의 카드입니다.
  • DisplayStyle PEEK인 경우 UI는 대신 현재 카드를 오버레이하는 부가기능 사이드바의 하단 미리보기 헤더 새 카드의 제목을 표시하고 새 카드를 볼지 여부를 결정합니다. 보기 버튼을 클릭하면 카드가 현재 카드를 교체합니다 (위에서 설명한 대로 REPLACE)을 입력합니다.

문맥 카드를 추가로 만들고 스택으로 푸시합니다 (다이어그램의 노란색 '푸시한 카드'). 업데이트 중 카드 스택이 부가기능 UI를 변경하여 최상위 카드를 표시합니다. 사용자가 스택의 컨텍스트 카드가 삭제되고 디스플레이는 최상위 비문맥 카드 또는 홈페이지에 업데이트됩니다.

사용자가 부가기능에서 정의할 수 없는 컨텍스트를 입력하는 경우 새 카드가 생성되지 않고 현재 카드가 계속 표시됩니다.

Navigation 작업 아래에 설명된 사항은 동일한 컨텍스트의 카드에만 적용됩니다. 예를 들어 popToRoot() 다른 모든 문맥 카드만 팝합니다. 홈페이지 카드에 영향을 미치지 않습니다.

반면에 버튼은 사용자는 언제든지 문맥 카드에서 사용할 수 없습니다.

다음에서 카드를 추가하거나 제거하여 카드 간에 전환을 만들 수 있습니다. 있습니다. Navigation 클래스는 스택에서 카드를 푸시하고 팝하는 함수를 제공합니다. 빌드하려면 효과적인 카드 탐색을 위해서는 widgets로 탐색 사용 작업을 수행할 수 있습니다. 튀어나오거나 여러 카드를 동시에 사용할 수 있지만 처음에 나오는 홈페이지 카드는 삭제할 수 없음 스택으로 가장 먼저 푸시되는 프로세스를 나타냅니다

위젯과의 사용자 상호작용에 응답하여 새 카드로 이동하려면 다음 단계를 따르세요. 다음 단계를 따르세요.

  1. Action 객체 만들기 인코더와 디코더를 콜백 함수 정의할 수 있습니다
  2. 위젯에 적절한 위젯 핸들러 함수 해당 위젯에 Action를 설정합니다.
  3. 탐색을 실행하는 콜백 함수를 구현합니다. 이 함수 액션 이벤트 객체가 제공됩니다 을 인수로 사용하고 다음을 실행해야 합니다. <ph type="x-smartling-placeholder">
      </ph>
    1. Navigation 만들기 객체를 사용하여 카드 변경을 정의합니다. 단일 Navigation 객체는 순서대로 수행되는 여러 탐색 단계가 포함됩니다. 객체에 추가됩니다.
    2. ActionResponse 빌드 객체를 사용하여 ActionResponseBuilder 클래스 및 Navigation 객체를 지정합니다.
    3. 빌드한 ActionResponse
를 통해 개인정보처리방침을 정의할 수 있습니다.

탐색 컨트롤을 만들 때 다음을 사용합니다. Navigation 객체 함수:

함수 설명
Navigation.pushCard(Card) 현재 스택으로 카드를 푸시합니다. 이를 위해서는 먼저 카드를 만들어야 합니다.
Navigation.popCard() 스택 맨 위에서 카드 한 장을 삭제합니다. 부가기능 헤더 행의 뒤로 화살표를 클릭하는 것과 같습니다. 루트 카드는 삭제되지 않습니다.
Navigation.popToRoot() 루트 카드를 제외한 모든 카드를 스택에서 삭제합니다. 기본적으로 카드 스택을 재설정합니다.
Navigation.popToNamedCard(String) 카드가 지정된 이름의 카드나 스택의 루트 카드에 도달할 때까지 스택에서 카드를 팝합니다. CardBuilder.setName(String) 함수를 사용하여 카드에 이름을 할당할 수 있습니다.
Navigation.updateCard(Card) 현재 카드를 인플레이스 교체하여 UI에 표시된 카드를 새로고침합니다.

사용자 상호작용이나 이벤트로 인해 동일한 UI에서 카드가 다시 렌더링되어야 하는 경우 컨텍스트에 맞게 Navigation.pushCard()님, Navigation.popCard(), 및 Navigation.updateCard() 메서드를 사용하여 기존 카드를 대체하세요. 사용자 상호작용 또는 이벤트가 다른 컨텍스트에서 카드를 다시 렌더링하려면 ActionResponseBuilder.setStateChanged() 드림 이러한 컨텍스트에서 부가기능을 강제로 다시 실행할 수 있습니다.

다음은 탐색의 예입니다.

  • 상호작용 또는 이벤트가 현재 카드의 상태를 변경하는 경우 (예: 작업 목록에 작업 추가) updateCard()
  • 상호작용 또는 이벤트가 추가 세부정보를 제공하거나 다음 사항을 요청하는 경우 추가 작업 (예: 세부정보 보기 또는 새 캘린더 일정을 만들기 위해 버튼 누르기) pushCard() 드림 를 사용하면 사용자가 뒤로 버튼을 클릭하세요.
  • 상호작용 또는 이벤트가 이전 카드에서 상태를 업데이트하는 경우 (예: 에서 항목 제목을 업데이트하는 경우 popCard()님, popCard(), pushCard(previous), 및 pushCard(current) 이전 카드와 현재 카드를 업데이트합니다.

카드 새로고침 중

Google Workspace 부가기능을 사용하면 다음에 등록된 Apps Script 트리거 함수를 다시 실행하여 카드를 새로고침합니다. 매니페스트를 참조하세요 사용자는 부가기능 메뉴 항목을 통해 이 새로고침을 트리거합니다.

Google Workspace 부가기능 사이드바

이 작업은 homepageTrigger님이 생성한 카드에 자동으로 추가됩니다. 부가기능의 매니페스트에 지정된 contextualTrigger 트리거 함수 파일 (문맥 및 비문맥 카드 스택의 '루트')

여러 카드 반품

부가기능 카드 예

홈페이지 또는 컨텍스트 트리거 함수는 빌드 및 반환에 사용됩니다. 단일 Card 객체 또는 Card 객체를 사용하여 애플리케이션 UI가 표시됩니다.

카드가 하나뿐인 경우 비문맥 또는 문맥 스택에 추가됩니다. 루트 카드로 사용하고 호스트 애플리케이션 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();
  }