이 문서에서는 Android Jetpack의 템플릿 빌더를 사용하여 Slice를 구성하는 방법을 자세히 설명합니다.
슬라이스 템플릿 정의
Slice는 ListBuilder
를 사용하여 구성됩니다. ListBuilder를 사용하면 목록에 표시되는 여러 유형의 행을 추가할 수 있습니다. 이 섹션에서는 각 행 유형 및 행이 구성되는 방법을 설명합니다.
SliceAction
Slice 템플릿의 가장 기본적인 요소는 SliceAction
입니다. SliceAction
은 PendingIntent
와 함께 라벨을 포함하며 다음 중 하나입니다.
- 아이콘 버튼
- 기본 전환
- 맞춤 전환(켜기/끄기 상태가 있는 드로어블)
SliceAction
은 이 섹션의 나머지 부분에서 설명하는 템플릿 빌더에 의해 사용됩니다. SliceAction
에서는 작업의 이미지가 표시되는 방식을 결정하는 이미지 모드를 정의할 수 있습니다.
ICON_IMAGE
: 크기가 아주 작고 색조를 조정할 수 있음SMALL_IMAGE
: 크기가 작고 색조를 조정할 수 없음LARGE_IMAGE
: 크기가 가장 크고 색조를 조정할 수 없음
HeaderBuilder
대부분의 경우 HeaderBuilder
를 사용하여 템플릿의 헤더를 설정해야 합니다.
헤더에는 다음을 포함할 수 있습니다.
- 제목
- 자막
- 요약 자막
- 기본 작업
다음은 몇 가지 헤더 구성 예입니다. 회색 상자는 잠재적 아이콘 및 패딩 위치를 나타냅니다.
다른 표면의 헤더 렌더링
Slice가 필요한 경우 표시 표면에 따라 Slice를 렌더링하는 방법이 결정됩니다. 호스팅하는 표면 간에 렌더링이 약간 다를 수도 있습니다.
더 작은 형식에서는 일반적으로 헤더만 표시됩니다(헤더가 있는 경우). 헤더 요약을 지정한 경우 자막 텍스트 대신 요약 텍스트가 표시됩니다.
템플릿에 헤더를 지정하지 않았다면 일반적으로 ListBuilder
에 추가된 첫 번째 행이 대신 표시됩니다.
HeaderBuilder 예 - 헤더가 있는 간단한 목록 Slice
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 ) } }
자바
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
Slice 헤더에 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) } }
자바
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, 아이콘 또는 타임스탬프
- 기본 작업
다음 제한사항에 따라 여러 가지 방법으로 행 콘텐츠를 조합할 수 있습니다.
- 시작 항목은 Slice의 첫 번째 행에 표시되지 않습니다.
- 종료 항목은
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) } } }
자바
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 } } } }
자바
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
를 사용하여 볼륨 슬라이더가 포함된 Slice를 만드는 방법을 보여줍니다. 진행률 표시줄 행을 구성하려면 addRange()
를 사용하세요.
Kotlin
fun createSliceWithRange(sliceUri: Uri): Slice { return list(context, sliceUri, ListBuilder.INFINITY) { inputRange { title = "Ring Volume" inputAction = volumeChangedPendingIntent max = 100 value = 30 } } }
자바
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()
에서 가능한 한 빠르게 Slice를 반환해야 합니다.
호출 시간이 오래 걸리면 깜박임 및 갑작스러운 크기 조절과 같은 디스플레이 문제가 발생할 수 있습니다.
빠르게 로드할 수 없는 Slice 콘텐츠가 있다면 빌더에서 콘텐츠가 로드 중임에 유의하면서 자리표시자 콘텐츠를 사용하여 Slice를 구성할 수 있습니다. 콘텐츠를 표시할 준비가 되면 Slice URI를 사용하여 getContentResolver().notifyChange(sliceUri, null)
을 호출합니다. 이렇게 하면 또 다른 SliceProvider.onBindSlice()
가 호출되어 새로운 콘텐츠로 Slice를 다시 구성할 수 있습니다.
지연 콘텐츠 예 - 직장으로 이동
아래의 직장으로 이동 예에서 직장까지의 거리는 동적으로 결정되며 즉시 사용하지 못할 수도 있습니다. 코드 예는 콘텐츠가 로드되는 동안 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) } } }
자바
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" ); }
Slice 내 사용 중지된 스크롤 처리
Slice 템플릿을 표시하는 표면은 템플릿 내에서 스크롤을 지원하지 않을 수 있습니다. 이 경우 일부 콘텐츠가 표시되지 않을 수도 있습니다.
예를 들어 Wi-Fi 네트워크 목록을 보여주는 Slice를 생각해 보세요.
Wi-Fi 목록이 길고 스크롤이 사용 중지된 경우 사용자가 목록의 모든 항목을 볼 수 있도록 더보기 버튼을 추가할 수 있습니다. 다음 예와 같이 addSeeMoreAction()
을 사용하여 이 버튼을 추가할 수 있습니다.
Kotlin
fun seeMoreActionSlice(sliceUri: Uri) = list(context, sliceUri, ListBuilder.INFINITY) { // [START_EXCLUDE] // [END_EXCLUDE] setSeeMoreAction(seeAllNetworksPendingIntent) // [START_EXCLUDE] // [END_EXCLUDE] }
자바
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" ) } }
자바
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(); }
이 메서드를 통해 추가된 행 또는 작업은 다음 조건 중 하나가 충족되는 때만 표시됩니다.
- Slice의 프레젠터가 뷰에서 스크롤을 사용 중지했습니다.
- 사용 가능한 공간에 일부 행을 표시할 수 없습니다.
템플릿 결합
여러 행 유형을 결합하여 서식 있는 동적 Slice를 만들 수 있습니다. 예를 들어 Slice에 헤더 행, 단일 이미지가 있는 그리드 및 텍스트 셀이 두 개 있는 그리드를 포함할 수 있습니다.
다음은 세 개의 셀이 포함된 그리드와 함께 헤더 행이 있는 Slice입니다.