이제 Android 11 개발자 프리뷰를 사용할 수 있습니다. 테스트해 보고 의견을 공유하세요.

슬라이스 템플릿

이 문서에서는 Android Jetpack의 템플릿 빌더를 사용하여 슬라이스를 구성하는 방법을 자세히 설명합니다.

슬라이스 템플릿 정의

슬라이스는 ListBuilder를 사용하여 구성됩니다. ListBuilder를 사용하면 목록에 표시되는 여러 유형의 행을 추가할 수 있습니다. 이 섹션에서는 각 행 유형 및 행이 구성되는 방법을 설명합니다.

SliceAction

슬라이스 템플릿의 가장 기본적인 요소는 SliceAction입니다. SliceAction에는 라벨과 PendingIntent가 포함되며 다음 중 하나입니다.

  • 아이콘 버튼
  • 기본 전환
  • 맞춤 전환(켜기/끄기 상태가 있는 드로어블)

SliceAction은 이 섹션의 나머지 부분에서 설명하는 템플릿 빌더에 의해 사용됩니다. SliceAction에서는 작업의 이미지가 표시되는 방식을 결정하는 이미지 모드를 정의할 수 있습니다.

  • ICON_IMAGE: 크기가 아주 작고 색조를 조정할 수 있음
  • SMALL_IMAGE: 크기가 작고 색조를 조정할 수 없음
  • LARGE_IMAGE: 크기가 가장 크고 색조를 조정할 수 없음

HeaderBuilder

대부분의 경우 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();
    }
    

헤더의 SliceAction

슬라이스 헤더에 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();
    }
    

RowBuilder

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

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를 사용하면 진행률 표시줄 또는 입력 범위(예: 슬라이더)가 포함된 행을 만들 수 있습니다.

다음 이미지에 진행률 표시줄 및 슬라이더 예가 표시되어 있습니다.

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에서 가능한 한 빠르게 슬라이스를 반환해야 합니다. 호출 시간이 오래 걸리면 깜박임 및 갑작스러운 크기 조절과 같은 디스플레이 문제가 발생할 수 있습니다.

빠르게 로드할 수 없는 슬라이스 콘텐츠가 있는 경우 빌더에서 콘텐츠가 로드 중임에 유의하면서 null 또는 자리표시자 콘텐츠를 사용하여 슬라이스를 구성할 수 있습니다. 콘텐츠를 표시할 준비가 되면 슬라이스 URI를 사용하여 getContentResolver().notifyChange(sliceUri, null)을 호출합니다. 이렇게 하면 SliceProvider#onBindSlice가 다시 호출되어 새로운 콘텐츠로 다시 슬라이스를 만들 수 있습니다.

지연 콘텐츠 예 - 직장으로 이동

아래의 직장으로 이동 예에서 직장까지의 거리는 동적으로 결정되며 즉시 사용하지 못할 수도 있습니다. 코드 예는 콘텐츠가 로드되는 동안 null 자막을 자리표시자로 사용하는 방법을 보여줍니다.

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

슬라이스 내 사용 중지된 스크롤 처리

슬라이스 템플릿을 표시하는 표면의 템플릿 내에서 스크롤 기능이 지원되지 않을 수도 있습니다. 이 경우 일부 콘텐츠가 표시되지 않을 수도 있습니다.

예를 들어 Wi-Fi 네트워크 목록을 보여주는 슬라이스를 예로 들어 보겠습니다.

Wi-Fi 목록이 길고 스크롤이 사용 중지된 경우 사용자가 목록의 모든 항목을 볼 수 있도록 더보기 버튼을 추가할 수 있습니다. 다음 예와 같이 addSeeMoreAction()을 사용하여 이 버튼을 추가할 수 있습니다.

Kotlin

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

Java

    public Slice seeMoreActionSlice(Uri sliceUri) {
        if (getContext() == null) {
            return null;
        }
        ListBuilder listBuilder = new ListBuilder(getContext(), sliceUri, ListBuilder.INFINITY);
        // ...
        listBuilder.setSeeMoreAction(seeAllNetworksPendingIntent);
        // ...
        return listBuilder.build();
    }
    

다음 이미지와 같이 표시됩니다.

더보기를 탭하면 seeAllNetworksPendingIntent가 전송됩니다.

또는 맞춤 메시지 또는 행을 제공하려면 RowBuilder를 추가해 보세요.

Kotlin

    fun seeMoreRowSlice(sliceUri: Uri) =
        list(context, sliceUri, ListBuilder.INFINITY) {
            // ...
            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)
                // ...
                .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"))
                );
        // ...
        return listBuilder.build();
    }
    

이 메서드를 통해 추가된 행 또는 작업은 다음 조건 중 하나가 충족되는 경우에만 표시됩니다.

  • 슬라이스의 프레젠터가 뷰에서 스크롤을 사용 중지했습니다.
  • 사용 가능한 공간에 일부 행을 표시할 수 없습니다.

템플릿 결합

여러 행 유형을 결합하여 서식 있는 동적 슬라이스를 만들 수 있습니다. 예를 들어 슬라이스에 헤더 행, 단일 이미지가 있는 그리드 및 텍스트 셀이 두 개 있는 그리드를 포함할 수 있습니다.

다음은 헤더 행 및 셀이 세 개 있는 그리드가 있는 슬라이스입니다.