التنقّل في البطاقة

يتم إنشاء معظم الإضافات المستندة إلى البطاقات باستخدام بطاقات متعددة تمثل "صفحات" مختلفة من واجهة الإضافة. للحصول على تجربة مستخدم فعالة، يجب عليك استخدام التنقل البسيط والطبيعي بين البطاقات في الإضافة الخاصة بك.

في إضافات Gmail، يتم التعامل مع الانتقالات بين البطاقات المختلفة لواجهة المستخدم من خلال دفع البطاقات وإبرازها من حزمة بطاقات واحدة، مع عرض البطاقة العلوية في Gmail من خلال Gmail.

التنقل في بطاقة الصفحة الرئيسية

تقدّم إضافات Google Workspace الصفحات الرئيسية والبطاقات غير السياقية. لاستيعاب البطاقات السياقية وغير السياقية، تتضمّن إضافات Google Workspace حزمة بطاقات داخلية لكل منها. عند فتح إضافة في مضيف، يتم تنشيط homepageTrigger المقابلة لإنشاء أول بطاقة الصفحة الرئيسية على الحزمة (بطاقة "الصفحة الرئيسية" ذات اللون الأزرق الداكن في الرسم التخطيطي أدناه). إذا لم يتم تحديد homepageTrigger، سيتم إنشاء بطاقة تلقائية وعرضها ودفعها إلى الحزمة غير السياقية. هذه البطاقة الأولى هي بطاقة جذر.

يمكن للإضافتك إنشاء بطاقات إضافية غير سياقية ووضعها على الحزمة ("البطاقات المدفوعة" الزرقاء في الرسم البياني) أثناء تنقّل المستخدم عبر الإضافة. تعرض واجهة مستخدم الإضافة البطاقة العلوية في الحزمة، وبالتالي يؤدي دفع البطاقات الجديدة إلى الحزمة إلى تغيير الشاشة، وإخراج البطاقات خارج الحزمة يؤدي إلى إعادة العرض إلى البطاقات السابقة.

إذا كانت الإضافة تحتوي على مشغِّل سياقي محدّد، عندما يُدخل المستخدم هذا السياق، يتم تنشيط المشغِّل. تُنشئ وظيفة التفعيل البطاقة السياقية، ولكن يتم تعديل طريقة عرض واجهة المستخدم استنادًا إلى DisplayStyle البطاقة الجديدة:

  • إذا كانت القيمة DisplayStyle هي REPLACE (البطاقة التلقائية)، ستحلّ بطاقة السياق (البطاقة "السياقية" ذات اللون البرتقالي الغامق في المخطّط) محلّ البطاقة المعروضة حاليًا. يؤدي هذا الإجراء إلى بدء تكديس بطاقة سياقية جديدة أعلى حِزم البطاقة غير السياقية، وهذه البطاقة السياقية هي بطاقة الجذر لحِزمة البطاقات السياقية.
  • أما إذا كان DisplayStyle هو PEEK، فستنشئ واجهة المستخدم بدلاً من ذلك عنوانًا خاطفًا يظهر في أسفل الشريط الجانبي للإضافة الإضافية على سطح البطاقة الحالية. يُظهر العنوان الخاطف عنوان البطاقة الجديدة ويوفر عناصر تحكم زر المستخدم التي تسمح لهم بتحديد ما إذا كانوا يريدون عرض البطاقة الجديدة أم لا. عند النقر على الزر عرض، سيتم استبدال البطاقة الحالية (كما هو موضّح أعلاه بالبطاقة REPLACE).

يمكنك إنشاء بطاقات سياقية إضافية ودفعها إلى الحزمة ("البطاقات المدفوعة" الصفراء في الرسم التخطيطي). يؤدي تحديث حزمة البطاقات إلى تغيير واجهة المستخدم للإضافة لعرض البطاقة العلوية. إذا ترك المستخدم سياقًا، تتم إزالة البطاقات السياقية على الحزمة ويتم تحديث العرض إلى آخر بطاقة أو صفحة رئيسية لا تستند إلى السياق.

إذا أدخل المستخدم سياقًا لا تحدّد إضافتك عامل تشغيل سياقي له، لن يتم إنشاء بطاقة جديدة وتبقى البطاقة الحالية معروضة.

لا تؤثر إجراءات Navigation الموضّحة أدناه إلا على البطاقات ذات السياق نفسه. على سبيل المثال، popToRoot() تظهر بطاقة سياقية فقط في جميع البطاقات السياقية الأخرى، ولن تؤثر في بطاقات الصفحة الرئيسية.

وفي المقابل، يكون زر متاحًا دائمًا للمستخدم للانتقال من بطاقات السياق إلى البطاقات غير السياقية.

يمكنك إنشاء انتقالات بين البطاقات عبر إضافة بطاقات أو إزالتها من تكديس البطاقات. توفّر فئة Navigation دوال لإرسال البطاقات وإبرازها من المجموعات. لإنشاء عناصر تنقل فعَّالة في البطاقة، يمكنك ضبط أدواتك لاستخدام إجراءات التنقل. يمكنك دفع بطاقات متعددة أو إبرازها في وقت واحد، ولكن لا يمكنك إزالة بطاقة الصفحة الرئيسية الأولية التي يتم دفعها أولاً إلى الحزمة عند بدء تشغيل الإضافة.

للانتقال إلى بطاقة جديدة استجابةً لتفاعل المستخدم مع أداة، اتّبِع الخطوات التالية:

  1. أنشئ كائن Action واربطه بدالة استدعاء تحدّدها.
  2. عليك استدعاء دالة معالج الأدوات المناسبة في الأداة لضبط Action على هذه الأداة.
  3. تنفيذ وظيفة معاودة الاتصال التي تجري التنقل. يتم منح هذه الدالة كائن حدث إجراء كوسيطة ويجب تنفيذ ما يلي:
    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) استبدال البطاقة الحالية في مكانها أو تجديد عرضها في واجهة المستخدم

إذا كان يجب أن يؤدي تفاعل المستخدم أو الحدث إلى إعادة عرض البطاقات في السياق نفسه، استخدِم طرق Navigation.pushCard() وNavigation.popCard() وNavigation.updateCard() لاستبدال البطاقات الحالية. إذا كان من المفترض أن يؤدي تفاعل المستخدم أو الحدث إلى إعادة عرض البطاقات في سياق مختلف، استخدِم ActionResponseBuilder.setStateChanged() لفرض إعادة تنفيذ الإضافة في تلك السياقات.

فيما يلي أمثلة على التنقل:

  • إذا أدى تفاعل أو حدث إلى تغيير حالة البطاقة الحالية (على سبيل المثال، إضافة مهمة إلى قائمة مهام)، استخدِم updateCard().
  • إذا كان أحد التفاعلات أو الأحداث يقدّم مزيدًا من التفاصيل أو يطلب من المستخدم اتخاذ إجراء آخر (مثل النقر على عنوان عنصر للاطّلاع على المزيد من التفاصيل أو الضغط على زر لإنشاء حدث جديد في "تقويم Google")، يمكنك استخدام pushCard() لعرض الصفحة الجديدة مع السماح للمستخدم بالخروج من الصفحة الجديدة باستخدام زر الرجوع.
  • إذا تم تعديل تفاعل أو حدث في بطاقة سابقة (على سبيل المثال، تعديل عنوان العنصر من خلال عرض التفاصيل)، استخدِم علامات مثل popCard() وpopCard() وpushCard(previous) وpushCard(current) لتعديل البطاقة السابقة والبطاقة الحالية.

جارٍ إعادة تحميل البطاقات

تمنح إضافات Google Workspace المستخدمين إمكانية إعادة تحميل بطاقتك من خلال إعادة تشغيل وظيفة مشغِّل "برمجة التطبيقات" المسجَّلة في البيان. يشغّل المستخدمون عملية إعادة التحميل هذه من خلال عنصر قائمة للإضافة:

الشريط الجانبي لإضافة 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();
  }