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

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

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

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