نماذج الشرائح

يقدّم هذا المستند تفاصيل عن كيفية استخدام أدوات إنشاء النماذج في Android Jetpack لإنشاء الشرائح.

تحديد نموذج الشريحة

يتم إنشاء الشرائح باستخدام ListBuilder. يتيح لك ListBuilder إضافة أنواع مختلفة من الصفوف المعروضة في القائمة. يصف هذا القسم كل نوع من أنواع الصفوف هذه وكيفية إنشائها.

SliceAction

إنّ العنصر الأساسي في نموذج "شريحة" هو SliceAction. يتضمّن SliceAction تصنيفًا بالإضافة إلى PendingIntent، وهو أحد ما يلي:

  • زر الرمز
  • مفتاح التبديل التلقائي
  • تبديل مخصّص (قابل للرسم مع حالة تفعيل/إيقاف)

يتم استخدام SliceAction من خلال منصات إنشاء النماذج الموضحة في بقية هذا القسم. يمكن أن يتضمّن SliceAction وضع صورة يحدّد كيفية عرض الصورة للإجراء:

  • ICON_IMAGE: حجم صغير وقابل للتلوين
  • SMALL_IMAGE: حجم صغير وغير قابل للتلوين
  • LARGE_IMAGE: أكبر حجم وغير قابل للتلوين

أداة إنشاء العناوين

في معظم الحالات، يجب تحديد عنوان للنموذج باستخدام HeaderBuilder. ويمكن أن يدعم العنوان ما يلي:

  • العنوان
  • العنوان الفرعي
  • العنوان الفرعي للملخّص
  • الإجراء الأساسي

في ما يلي بعض الأمثلة على عمليات ضبط العناوين. لاحظ أن المربعات الرمادية تعرض الأيقونات المحتملة وأماكن المساحة المتروكة:

عرض العنوان على مساحات مختلفة

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

في التنسيقات الأصغر، يتم عادةً عرض العنوان فقط، إن وجد. إذا حددت ملخصًا للعنوان، فسيتم عرض نص الملخص بدلاً من نص العنوان الفرعي.

إذا لم تحدد عنوانًا في النموذج، يتم عادةً عرض الصف الأول المُضاف إلى ListBuilder بدلاً من ذلك.

مثال على HeaderBuilder - قائمة بسيطة تحتوي على عنوان

Kotlin

fun createSliceWithHeader(sliceUri: Uri) =
    list(context, sliceUri, ListBuilder.INFINITY) {
        setAccentColor(0xff0F9D) // Specify color for tinting icons
        header {
            title = "Get a ride"
            subtitle = "Ride in 4 min"
            summary = "Work in 1 hour 45 min | Home in 12 min"
        }
        row {
            title = "Home"
            subtitle = "12 miles | 12 min | $9.00"
            addEndItem(
                IconCompat.createWithResource(context, R.drawable.ic_home),
                ListBuilder.ICON_IMAGE
            )
        }
    }

Java

public Slice createSliceWithHeader(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }

    // Construct the parent.
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            .setAccentColor(0xff0F9D58) // Specify color for tinting icons.
            .setHeader( // Create the header and add to slice.
                    new HeaderBuilder()
                            .setTitle("Get a ride")
                            .setSubtitle("Ride in 4 min.")
                            .setSummary("Work in 1 hour 45 min | Home in 12 min.")
            ).addRow(new RowBuilder() // Add a row.
                    .setPrimaryAction(
                            createActivityAction()) // A slice always needs a SliceAction.
                    .setTitle("Home")
                    .setSubtitle("12 miles | 12 min | $9.00")
                    .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.ic_home),
                            SliceHints.ICON_IMAGE)
            ); // Add more rows if needed...
    return listBuilder.build();
}

إجراءات الشرائح في العناوين

يمكن لعناوين الشرائح أيضًا عرض SliceActions:

Kotlin

fun createSliceWithActionInHeader(sliceUri: Uri): Slice {
    // Construct our slice actions.
    val noteAction = SliceAction.create(
        takeNoteIntent,
        IconCompat.createWithResource(context, R.drawable.ic_pencil),
        ICON_IMAGE,
        "Take note"
    )

    val voiceNoteAction = SliceAction.create(
        voiceNoteIntent,
        IconCompat.createWithResource(context, R.drawable.ic_mic),
        ICON_IMAGE,
        "Take voice note"
    )

    val cameraNoteAction = SliceAction.create(
        cameraNoteIntent,
        IconCompat.createWithResource(context, R.drawable.ic_camera),
        ICON_IMAGE,
        "Create photo note"
    )

    // Construct the list.
    return list(context, sliceUri, ListBuilder.INFINITY) {
        setAccentColor(0xfff4b4) // Specify color for tinting icons
        header {
            title = "Create new note"
            subtitle = "Easily done with this note taking app"
        }
        addAction(noteAction)
        addAction(voiceNoteAction)
        addAction(cameraNoteAction)
    }
}

Java

public Slice createSliceWithActionInHeader(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    // Construct our slice actions.
    SliceAction noteAction = SliceAction.create(takeNoteIntent,
            IconCompat.createWithResource(getContext(), R.drawable.ic_pencil),
            ListBuilder.ICON_IMAGE, "Take note");

    SliceAction voiceNoteAction = SliceAction.create(voiceNoteIntent,
            IconCompat.createWithResource(getContext(), R.drawable.ic_mic),
            ListBuilder.ICON_IMAGE,
            "Take voice note");

    SliceAction cameraNoteAction = SliceAction.create(cameraNoteIntent,
            IconCompat.createWithResource(getContext(), R.drawable.ic_camera),
            ListBuilder.ICON_IMAGE,
            "Create photo note");


    // Construct the list.
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            .setAccentColor(0xfff4b400) // Specify color for tinting icons
            .setHeader(new HeaderBuilder() // Construct the header.
                    .setTitle("Create new note")
                    .setSubtitle("Easily done with this note taking app")
            )
            .addRow(new RowBuilder()
                    .setTitle("Enter app")
                    .setPrimaryAction(createActivityAction())
            )
            // Add the actions to the ListBuilder.
            .addAction(noteAction)
            .addAction(voiceNoteAction)
            .addAction(cameraNoteAction);
    return listBuilder.build();
}

أداة إنشاء الصفوف

يمكنك إنشاء صف من المحتوى باستخدام RowBuilder. يمكن أن يدعم الصف أيًا مما يلي:

  • العنوان
  • العنوان الفرعي
  • عنصر البداية: SliceAction أو الرمز أو الطابع الزمني
  • عناصر النهاية: SliceAction أو الرمز أو الطابع الزمني
  • الإجراء الأساسي

يمكنك دمج محتوى الصفوف بعدة طرق، وفقًا للقيود التالية:

  • لن تظهر عناصر البداية في الصف الأول من شريحة
  • لا يمكن أن تكون العناصر النهائية مزيجًا من SliceAction عناصر وIcon عناصر.
  • يمكن أن يحتوي الصف على طابع زمني واحد فقط.

تظهر صفوف المحتوى النموذجية في الصور التالية. لاحظ أن المربعات الرمادية تعرض الأيقونات المحتملة وأماكن المساحة المتروكة:

مثال على RowBuilder - تبديل Wi-Fi

يوضّح المثال أدناه صفًا يحتوي على إجراء أساسي ومفتاح تبديل تلقائي.

Kotlin

fun createActionWithActionInRow(sliceUri: Uri): Slice {
    // Primary action - open wifi settings.
    val wifiAction = SliceAction.create(
        wifiSettingsPendingIntent,
        IconCompat.createWithResource(context, R.drawable.ic_wifi),
        ICON_IMAGE,
        "Wi-Fi Settings"
    )

    // Toggle action - toggle wifi.
    val toggleAction = SliceAction.createToggle(
        wifiTogglePendingIntent,
        "Toggle Wi-Fi",
        isConnected /* isChecked */
    )

    // Create the parent builder.
    return list(context, wifiUri, ListBuilder.INFINITY) {
        setAccentColor(0xff4285) // Specify color for tinting icons / controls.
        row {
            title = "Wi-Fi"
            primaryAction = wifiAction
            addEndItem(toggleAction)
        }
    }
}

Java

public Slice createActionWithActionInRow(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    // Primary action - open wifi settings.
    SliceAction primaryAction = SliceAction.create(wifiSettingsPendingIntent,
            IconCompat.createWithResource(getContext(), R.drawable.ic_wifi),
            ListBuilder.ICON_IMAGE,
            "Wi-Fi Settings"
    );

    // Toggle action - toggle wifi.
    SliceAction toggleAction = SliceAction.createToggle(wifiTogglePendingIntent,
            "Toggle Wi-Fi", isConnected /* isChecked */);

    // Create the parent builder.
    ListBuilder listBuilder = new ListBuilder(getContext(), wifiUri, ListBuilder.INFINITY)
            // Specify color for tinting icons / controls.
            .setAccentColor(0xff4285f4)
            // Create and add a row.
            .addRow(new RowBuilder()
                    .setTitle("Wi-Fi")
                    .setPrimaryAction(primaryAction)
                    .addEndItem(toggleAction));
    // Build the slice.
    return listBuilder.build();
}

أداة إنشاء الشبكات

يمكنك إنشاء شبكة من المحتوى باستخدام GridBuilder. يمكن أن تدعم الشبكة أنواع الصور التالية:

  • ICON_IMAGE: حجم صغير وقابل للتلوين
  • SMALL_IMAGE: حجم صغير وغير قابل للتلوين
  • LARGE_IMAGE: أكبر حجم وغير قابل للتلوين

يتم إنشاء خلية شبكة باستخدام CellBuilder. يمكن أن تدعم الخلية ما يصل إلى سطرين من النص وصورة واحدة. لا يمكن أن تكون الخلية فارغة.

تظهر أمثلة الشبكة في الصور التالية:

مثال على GridRowBuilder - المطاعم المجاورة

يوضح المثال أدناه صفًا على شكل شبكة يحتوي على صور ونص.

Kotlin

fun createSliceWithGridRow(sliceUri: Uri): Slice {
    // Create the parent builder.
    return list(context, sliceUri, ListBuilder.INFINITY) {
        header {
            title = "Famous restaurants"
            primaryAction = SliceAction.create(
                pendingIntent, icon, ListBuilder.ICON_IMAGE, "Famous restaurants"
            )
        }
        gridRow {
            cell {
                addImage(image1, LARGE_IMAGE)
                addTitleText("Top Restaurant")
                addText("0.3 mil")
                contentIntent = intent1
            }
            cell {
                addImage(image2, LARGE_IMAGE)
                addTitleText("Fast and Casual")
                addText("0.5 mil")
                contentIntent = intent2
            }
            cell {
                addImage(image3, LARGE_IMAGE)
                addTitleText("Casual Diner")
                addText("0.9 mi")
                contentIntent = intent3
            }
            cell {
                addImage(image4, LARGE_IMAGE)
                addTitleText("Ramen Spot")
                addText("1.2 mi")
                contentIntent = intent4
            }
        }
    }
}

Java

public Slice createSliceWithGridRow(Uri sliceUri) {
      if (getContext() == null) {
          return null;
      }
      // Create the parent builder.
      ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
              .setHeader(
                      // Create the header.
                      new HeaderBuilder()
                              .setTitle("Famous restaurants")
                              .setPrimaryAction(SliceAction
                                      .create(pendingIntent, icon, ListBuilder.ICON_IMAGE,
                                              "Famous restaurants"))
              )
              // Add a grid row to the list.
              .addGridRow(new GridRowBuilder()
                      // Add cells to the grid row.
                      .addCell(new CellBuilder()
                              .addImage(image1, ListBuilder.LARGE_IMAGE)
                              .addTitleText("Top Restaurant")
                              .addText("0.3 mil")
                              .setContentIntent(intent1)
                      ).addCell(new CellBuilder()
                              .addImage(image2, ListBuilder.LARGE_IMAGE)
                              .addTitleText("Fast and Casual")
                              .addText("0.5 mil")
                              .setContentIntent(intent2)
                      )
                      .addCell(new CellBuilder()
                              .addImage(image3, ListBuilder.LARGE_IMAGE)
                              .addTitleText("Casual Diner")
                              .addText("0.9 mi")
                              .setContentIntent(intent3))
                      .addCell(new CellBuilder()
                              .addImage(image4, ListBuilder.LARGE_IMAGE)
                              .addTitleText("Ramen Spot")
                              .addText("1.2 mi")
                              .setContentIntent(intent4))
                      // Every slice needs a primary action.
                      .setPrimaryAction(createActivityAction())
              );
      return listBuilder.build();
  }

مصمم النطاق

باستخدام RangeBuilder، يمكنك إنشاء صف يحتوي إما على شريط تقدّم أو نطاق إدخال، مثل شريط تمرير.

يتم عرض أمثلة عن التقدم وشريط التمرير في الصور التالية:

مثال على أداة RangeBuilder - شريط التمرير

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

Kotlin

fun createSliceWithRange(sliceUri: Uri): Slice {
    return list(context, sliceUri, ListBuilder.INFINITY) {
        inputRange {
            title = "Ring Volume"
            inputAction = volumeChangedPendingIntent
            max = 100
            value = 30
        }
    }
}

Java

public Slice createSliceWithRange(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    // Construct the parent.
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            .addRow(new RowBuilder() // Every slice needs a row.
                    .setTitle("Enter app")
                      // Every slice needs a primary action.
                    .setPrimaryAction(createActivityAction())
            )
            .addInputRange(new InputRangeBuilder() // Create the input row.
                    .setTitle("Ring Volume")
                    .setInputAction(volumeChangedPendingIntent)
                    .setMax(100)
                    .setValue(30)
            );
    return listBuilder.build();
}

المحتوى المتأخر

يجب إرجاع شريحة في أسرع وقت ممكن من SliceProvider.onBindSlice(). قد تؤدي المكالمات التي تستغرق وقتًا طويلاً إلى حدوث مشاكل في العرض، مثل الوميض وتغيير الحجم بشكل مفاجئ.

إذا كان لديك محتوى شريحة لا يمكن تحميله بسرعة، يمكنك إنشاء الشريحة بمحتوى عنصر نائب مع ملاحظة أنّه يتم تحميل المحتوى في أداة الإنشاء. عندما يصبح المحتوى جاهزًا للعرض، اتّصِل بـ getContentResolver().notifyChange(sliceUri, null) باستخدام معرّف الموارد المنتظم (URI) الخاص بالشريحة. يؤدي ذلك إلى طلب آخر على SliceProvider.onBindSlice()، حيث يمكنك إنشاء الشريحة مرة أخرى بمحتوى جديد.

مثال على المحتوى المتأخر - الذهاب إلى العمل

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

Kotlin

fun createSliceShowingLoading(sliceUri: Uri): Slice {
    // We’re waiting to load the time to work so indicate that on the slice by
    // setting the subtitle with the overloaded method and indicate true.
    return list(context, sliceUri, ListBuilder.INFINITY) {
        row {
            title = "Ride to work"
            setSubtitle(null, true)
            addEndItem(IconCompat.createWithResource(context, R.drawable.ic_work), ICON_IMAGE)
        }
    }
}

Java

public Slice createSliceShowingLoading(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    // Construct the parent.
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            // Construct the row.
            .addRow(new RowBuilder()
                    .setPrimaryAction(createActivityAction())
                    .setTitle("Ride to work")
                    // We’re waiting to load the time to work so indicate that on the slice by
                    // setting the subtitle with the overloaded method and indicate true.
                    .setSubtitle(null, true)
                    .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.ic_work),
                            ListBuilder.ICON_IMAGE)
            );
    return listBuilder.build();
}

private SliceAction createActivityAction() {
    return SliceAction.create(
            PendingIntent.getActivity(
                    getContext(),
                    0,
                    new Intent(getContext(), MainActivity.class),
                    0
            ),
            IconCompat.createWithResource(getContext(), R.drawable.ic_home),
            ListBuilder.ICON_IMAGE,
            "Enter app"
    );
}

الاسم المعرِّف غير مفعَّل أثناء التمرير ضمن الشريحة

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

كمثال، ضع في الاعتبار شريحة تعرض قائمة بشبكات WiFi:

إذا كانت قائمة WiFi طويلة، وكان التمرير غير مفعّل، يمكنك إضافة الزر عرض المزيد لضمان توفير طريقة للمستخدمين للاطّلاع على جميع العناصر في القائمة. يمكنك إضافة هذا الزر باستخدام addSeeMoreAction()، كما هو موضّح في المثال التالي:

Kotlin

fun seeMoreActionSlice(sliceUri: Uri) =
    list(context, sliceUri, ListBuilder.INFINITY) {
        // [START_EXCLUDE]
        // [END_EXCLUDE]
        setSeeMoreAction(seeAllNetworksPendingIntent)
        // [START_EXCLUDE]
        // [END_EXCLUDE]
    }

Java

public Slice seeMoreActionSlice(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY);
    // [START_EXCLUDE]
    listBuilder.addRow(new RowBuilder()
            .setTitle("Hello")
            .setPrimaryAction(createActivityAction())
    );
    // [END_EXCLUDE]
    listBuilder.setSeeMoreAction(seeAllNetworksPendingIntent);
    // [START_EXCLUDE]
    // [END_EXCLUDE]
    return listBuilder.build();
}

يظهر هذا كما هو موضح في الصورة التالية:

يؤدي النقر على عرض المزيد إلى إرسال seeAllNetworksPendingIntent.

بدلاً من ذلك، إذا كنت تريد تقديم رسالة أو صف مخصّصَين، يمكنك إضافة RowBuilder:

Kotlin

fun seeMoreRowSlice(sliceUri: Uri) =
    list(context, sliceUri, ListBuilder.INFINITY) {
        // [START_EXCLUDE]
        // [END_EXCLUDE]
        seeMoreRow {
            title = "See all available networks"
            addEndItem(
                IconCompat.createWithResource(context, R.drawable.ic_right_caret), ICON_IMAGE
            )
            primaryAction = SliceAction.create(
                seeAllNetworksPendingIntent,
                IconCompat.createWithResource(context, R.drawable.ic_wifi),
                ListBuilder.ICON_IMAGE,
                "Wi-Fi Networks"
            )
        }
    }

Java

public Slice seeMoreRowSlice(Uri sliceUri) {
    if (getContext() == null) {
        return null;
    }
    ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY)
            // [START_EXCLUDE]
            .addRow(new RowBuilder()
                    .setTitle("Hello")
                    .setPrimaryAction(createActivityAction())
            )
            // [END_EXCLUDE]
            .setSeeMoreRow(new RowBuilder()
                    .setTitle("See all available networks")
                    .addEndItem(IconCompat
                                    .createWithResource(getContext(), R.drawable
                                            .ic_right_caret),
                            ListBuilder.ICON_IMAGE)
                    .setPrimaryAction(SliceAction.create(seeAllNetworksPendingIntent,
                            IconCompat.createWithResource(getContext(), R.drawable.ic_wifi),
                            ListBuilder.ICON_IMAGE,
                            "Wi-Fi Networks"))
            );
    // [START_EXCLUDE]
    // [END_EXCLUDE]
    return listBuilder.build();
}

لا يتم عرض الصف أو الإجراء الذي تمت إضافته بهذه الطريقة إلا عند استيفاء أحد الشروط التالية:

  • أوقف مقدِّم الشريحة إمكانية التمرير في العرض.
  • لا يمكن عرض بعض صفوفك في المساحة المتاحة.

دمج النماذج

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

إليك شريحة بصف عنوان بالإضافة إلى شبكة تحتوي على ثلاث خلايا.