Mẫu lát cắt

Tài liệu này cung cấp thông tin chi tiết về cách sử dụng trình tạo mẫu trong Android Jetpack để tạo Lát cắt.

Xác định mẫu Lát cắt

Lát cắt được tạo bằng cách sử dụng ListBuilder. ListBuilder cho phép bạn thêm các loại hàng hiển thị trong danh sách. Phần này mô tả từng loại hàng đó và cách tạo các hàng đó.

Thao tác cắt lát

Phần tử cơ bản nhất của mẫu Lát cắt là SliceAction. SliceAction chứa nhãn cùng với PendingIntent và là một trong những nội dung sau:

  • Nút biểu tượng
  • Bật/tắt mặc định
  • Bật/tắt tuỳ chỉnh (một đối tượng có thể vẽ ở trạng thái bật/tắt)

Trình tạo mẫu sử dụng SliceAction được mô tả trong phần còn lại của phần này. SliceAction có thể xác định chế độ hình ảnh giúp xác định cách hình ảnh hiển thị cho thao tác:

  • ICON_IMAGE: kích thước nhỏ và có thể phủ màu
  • SMALL_IMAGE: kích thước nhỏ và không thể phủ màu
  • LARGE_IMAGE: kích thước lớn nhất và không thể phủ màu

Trình tạo tiêu đề

Trong hầu hết trường hợp, bạn nên đặt tiêu đề cho mẫu bằng cách sử dụng HeaderBuilder. Tiêu đề có thể hỗ trợ những nội dung sau:

  • Tiêu đề
  • Phụ đề
  • Tiêu đề phụ của tóm tắt
  • Tác vụ chính

Dưới đây là một số ví dụ về cấu hình tiêu đề. Lưu ý rằng các hộp màu xám cho thấy các vị trí tiềm năng của biểu tượng và khoảng đệm:

Kết xuất tiêu đề trên nhiều nền tảng

Khi cần một Lát cắt, giao diện hiển thị sẽ xác định cách hiển thị Lát cắt. Xin lưu ý rằng kết xuất có thể khác nhau đôi chút giữa các nền tảng lưu trữ.

Ở định dạng nhỏ hơn, thường chỉ tiêu đề được hiển thị, nếu có. Nếu bạn đã chỉ định một bản tóm tắt cho tiêu đề, thì văn bản tóm tắt sẽ xuất hiện thay vì văn bản phụ đề.

Nếu bạn chưa chỉ định tiêu đề trong mẫu, thì hàng đầu tiên được thêm vào ListBuilder thường sẽ hiển thị.

Ví dụ về HeaderBuilder – Lát cắt danh sách đơn giản có tiêu đề

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();
}

SliceAction trong tiêu đề

Tiêu đề của Lát cắt cũng có thể hiển thị SliceAction:

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();
}

Trình tạo hàng

Bạn có thể tạo một hàng nội dung bằng cách sử dụng RowBuilder. Một hàng có thể hỗ trợ bất kỳ nội dung nào sau đây:

  • Tiêu đề
  • Phụ đề
  • Mục bắt đầu: SliceAction, Biểu tượng hoặc dấu thời gian
  • Mục kết thúc: SliceAction, Biểu tượng hoặc dấu thời gian
  • Tác vụ chính

Bạn có thể kết hợp nội dung trong hàng theo nhiều cách, tuỳ thuộc vào các hạn chế sau:

  • Các mục bắt đầu sẽ không xuất hiện trên hàng đầu tiên của Lát cắt
  • Mục kết thúc không được kết hợp giữa đối tượng SliceAction và đối tượng Icon
  • Một hàng chỉ có thể chứa một dấu thời gian

Hàng nội dung mẫu được hiển thị trong các hình ảnh sau. Lưu ý rằng các hộp màu xám cho thấy vị trí tiềm năng của biểu tượng và khoảng đệm:

Ví dụ về RowBuilder – Bật/tắt Wi-Fi

Ví dụ bên dưới minh hoạ một hàng có hành động chính và nút bật/tắt mặc định.

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();
}

Trình tạo lưới

Bạn có thể xây dựng lưới nội dung bằng cách sử dụng GridBuilder. Lưới có thể hỗ trợ các loại hình ảnh sau:

  • ICON_IMAGE: kích thước nhỏ và có thể phủ màu
  • SMALL_IMAGE: kích thước nhỏ và không thể phủ màu
  • LARGE_IMAGE: kích thước lớn nhất và không thể phủ màu

Ô lưới được tạo bằng cách dùng CellBuilder. Một ô có thể hỗ trợ tối đa 2 dòng văn bản và một hình ảnh. Không được để trống ô.

Ví dụ về lưới được minh hoạ trong các hình ảnh sau đây:

Ví dụ về GridRowBuilder – Nhà hàng lân cận

Ví dụ bên dưới minh hoạ một hàng lưới chứa hình ảnh và văn bản.

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();
  }

Trình tạo dải ô

Với RangeBuilder, bạn có thể tạo một hàng chứa thanh tiến trình hoặc dải ô dữ liệu đầu vào, chẳng hạn như thanh trượt.

Ví dụ về tiến trình và thanh trượt được minh hoạ trong các hình sau:

Ví dụ về RangeBuilder – Thanh trượt

Ví dụ bên dưới minh hoạ cách tạo một Lát cắt chứa thanh trượt âm lượng bằng cách sử dụng InputRangeBuilder. Để tạo hàng tiến trình, hãy sử dụng 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();
}

Nội dung bị phát trễ

Bạn nên trả về một Lát cắt càng nhanh càng tốt từ SliceProvider.onBindSlice(). Các lệnh gọi tốn thời gian có thể gây ra các sự cố hiển thị, chẳng hạn như nhấp nháy và đổi kích thước đột ngột.

Nếu không thể tải nhanh nội dung Lát cắt, bạn có thể tạo Lát cắt bằng nội dung phần giữ chỗ, đồng thời lưu ý trong trình tạo rằng nội dung đang tải. Sau khi nội dung sẵn sàng để hiển thị, hãy gọi getContentResolver().notifyChange(sliceUri, null) bằng cách sử dụng URI Lát cắt. Điều này dẫn đến một lệnh gọi khác đến SliceProvider.onBindSlice(), tại đó bạn có thể tạo lại Lát cắt với nội dung mới.

Ví dụ về nội dung bị trễ – Đi xe đến cơ quan

Trong hàng Đi đến nơi làm việc bên dưới, khoảng cách đến cơ quan được xác định một cách linh động và có thể chưa có sẵn ngay lập tức. Mã ví dụ minh hoạ việc sử dụng tiêu đề phụ rỗng làm phần giữ chỗ trong khi nội dung tải:

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"
    );
}

Xử lý thao tác cuộn bị vô hiệu hoá trong Lát cắt

Nền tảng trình bày mẫu Lát cắt có thể không hỗ trợ tính năng cuộn trong mẫu. Trong trường hợp này, một số nội dung của bạn có thể không được hiển thị.

Chẳng hạn, hãy xem xét một Lát cắt cho thấy danh sách mạng Wi-Fi:

Nếu danh sách Wi-Fi dài và nếu tính năng cuộn bị tắt, bạn có thể thêm nút Xem thêm để đảm bảo rằng người dùng có cách xem được tất cả các mục trong danh sách. Bạn có thể thêm nút này bằng cách sử dụng addSeeMoreAction(), như trong ví dụ sau:

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();
}

Bố cục này hiển thị như trong hình sau:

Khi nhấn vào Xem thêm, bạn sẽ gửi seeAllNetworksPendingIntent.

Ngoài ra, nếu bạn muốn cung cấp một hàng hoặc thông báo tuỳ chỉnh, hãy cân nhắc việc thêm một 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();
}

Hàng hoặc hành động được thêm qua phương thức này chỉ hiển thị khi đáp ứng một trong các điều kiện sau:

  • Người trình bày Lát cắt của bạn đã tắt tính năng cuộn trên khung hiển thị
  • Không phải tất cả các hàng của bạn đều có thể hiển thị trong không gian có sẵn

Kết hợp các mẫu

Bạn có thể tạo một Lát cắt linh động và đa dạng bằng cách kết hợp nhiều loại hàng. Ví dụ: một Lát cắt có thể chứa một hàng tiêu đề, một lưới có một hình ảnh và một lưới có 2 ô văn bản.

Đây là một Lát cắt có hàng tiêu đề cùng với lưới chứa 3 ô.