List Picker¶
Applications often present a long list of items and allow users to express their choice in either single or multiple selections.
List Picker
is designed to handle such a complex list with ease and allows developers to:
- Set custom views to present the target items.
- Bind items by their position.
- Track user interactions and selections and notify the application of the changes using callbacks.
The List Picker
is displayed in a Bottom Sheet
when viewed on a phone and in an Alert Dialog
when viewed on a tablet.
List Picker
on phone:
List Picker
on tablet:
It can be configured to allow:
- Single selection: Presents the list of items with radio buttons and allows only one selection.
- Multi selection: Presents the list of items with check boxes and allows users to make multiple selections.
API¶
The ListPicker
Composable
is the main entry point for displaying the list. Its API is as follows:
@Composable
fun ListPicker(
items: @RawValue List<ListPickerItem>,
data: ListPickerData,
modifier: Modifier = Modifier,
onSelectionUpdated: ((Set<Int>) -> Unit)? = null,
colors: ListPickerColors = ListPickerDefaults.colors(),
textStyles: ListPickerTextStyles = ListPickerDefaults.textStyles()
)
The three main parameters of the ListPicker
Composable
are the ListPickerItem
items
, the ListPickerData
data
and the onSelectionUpdated
Lambda
, of which the first two are required parameters. They are described in more detail below:
The ListPickerItem
Data Class
is used to define the items in the list. It accepts any Composable
which is then displayed as the list item.
data class ListPickerItem(
val item: @RawValue @Composable () -> Unit,
val contentDescription: CharSequence
)
The ListPickerData
Data Class
defines the behavior of the List Picker
. It is used to set the List Picker
properties, such as label, whether it is single-select or multi-select, the picker's title and more.
data class ListPickerData(
val enabled: Boolean = true,
val label: CharSequence? = null,
val displayValue: CharSequence? = null,
val hint: CharSequence? = null,
val pickerTitle: CharSequence? = null,
val isSingleSelect: Boolean = false,
val showExpanded: Boolean = false,
val showSelectorOnStart: Boolean = true,
val autoSaveSelection: Boolean = false,
val anchorButtonText: CharSequence? = null,
val selectedItems: MutableSet<Int> = mutableSetOf(),
val selectedSectionData: @RawValue SelectedSectionData = SelectedSectionData(),
val exitDialogData: @RawValue ExitDialogData = ExitDialogData(),
val footerData: @RawValue FooterData = FooterData(),
val validationData: @RawValue ValidationData = ValidationData()
)
The onSelectionUpdated
parameter is a Lambda
expression that returns a Set
of the indices of the items selected by the user.
val onSelectionUpdatedLambda: (Set<Int>) -> Unit = { selectedList ->
// Do something with the selectedList e.g. update the display value based on the selections
updateDisplayValue(selectedList)
}
Usage in an Application¶
A basic example of how to use the List Picker
in an application is as follows:
// Function to create a list of Text items
fun stringListPickerItemList(count: Int): List<ListPickerItem> {
val textList = mutableListOf<ListPickerItem>()
for (i in 0 until count) {
val textItem = "Item $i"
textList.add(ListPickerItem(item = {
Text(text = textItem,
modifier = Modifier.clearAndSetSemantics { })
}, contentDescription = textItem))
}
return textList
}
val listOfString = stringListPickerItemList(100)
// Value to be displayed for the selected items
var displayValue by rememberSaveable {
mutableStateOf("")
}
// Lambda to update the display value when user selection changes
val onSelectionUpdated: (Set<Int>) -> Unit = { selectedList ->
displayValue = formatDisplayValue(listOfString, selectedList)
}
// Function to format the display value
fun formatDisplayValue(dataList: List<Any>, selectedList: Set<Int>): String {
var displayValue = ""
if (selectedList.isEmpty()) {
displayValue = ""
} else {
for ((index, value) in selectedList.withIndex()) {
var item = dataList[value]
displayValue = if (index == 0) {
item.toString()
} else {
"$displayValue, $item"
}
}
}
return displayValue
}
// Actual List Picker Composable
@Composable
ListPicker(
items = listOfString,
data = ListPickerData(
label = "Multi Selection List Picker",
hint = "Select",
pickerTitle = "Select Item",
displayValue = displayValue
),
onSelectionUpdated = onSelectionUpdated
)
List Picker for String Items¶
The SDK also provides a convenience ListPicker
Composable
which can be used for String
items. This API accepts a List
of String
instead of a List
of ListPickerItem
.
@Composable
fun ListPicker(
stringItems: List<String>,
data: ListPickerData,
modifier: Modifier = Modifier,
onSelectionUpdated: ((Set<Int>) -> Unit)? = null,
colors: ListPickerColors = ListPickerDefaults.colors(),
textStyles: ListPickerTextStyles = ListPickerDefaults.textStyles()
)
And this can then be used as follows:
// Function to create list of Strings
fun stringList(count: Int): List<String> {
val stringList = mutableListOf<String>()
for (i in 0 until count) {
stringList.add("Item $i")
}
return stringList
}
val listOfString = stringList(100)
// Value to be displayed for the selected items
var displayValue by rememberSaveable {
mutableStateOf("")
}
// Lambda to update the display value when user selection changes
val onSelectionUpdated: (Set<Int>) -> Unit = { selectedList ->
displayValue = formatDisplayValue(listOfString, selectedList)
}
// Function to format the display value
fun formatDisplayValue(dataList: List<Any>, selectedList: Set<Int>): String {
var displayValue = ""
if (selectedList.isEmpty()) {
displayValue = ""
} else {
for ((index, value) in selectedList.withIndex()) {
var item = dataList[value]
displayValue = if (index == 0) {
item.toString()
} else {
"$displayValue, $item"
}
}
}
return displayValue
}
// Actual List Picker Composable
@Composable
ListPicker(
stringItems = listOfString,
data = ListPickerData(
label = "Multi Selection List Picker",
hint = "Select",
pickerTitle = "Select Item",
displayValue = displayValue
),
onSelectionUpdated = onSelectionUpdated
)
List Picker Validation¶
List Picker
supports a validation icon and message that can be used to validate user input. This can be configured using the ValidationData
Data Class
. Default icons are provided as well, based on whether error is enabled or not.
data class ValidationData(
val enabled: Boolean = false,
val isError: Boolean = false,
val message: CharSequence? = null,
val icon: FioriIcon? = FioriIcon(
resId = if (isError) {
R.drawable.ic_sap_icon_hint
} else {
R.drawable.ic_sap_icon_accept
}
)
)
To show an error icon and message:
@Composable
ListPicker(
stringItems = stringList,
data = ListPickerData(
label = "Validation List Picker",
hint = "Select",
pickerTitle = "Choose Item",
isSingleSelect = true,
validationData = ValidationData(
enabled = true,
isError = true,
message = "Please select at least one option"
)
)
)
To show a regular validation icon and message:
@Composable
ListPicker(
stringItems = stringList,
data = ListPickerData(
label = "Validation List Picker",
hint = "Select",
pickerTitle = "Choose Item",
isSingleSelect = true,
validationData = ValidationData(
enabled = true,
isError = false,
message = "Option selected"
)
)
)
Expanded List Picker in Phone¶
By default, the List Picker
is displayed in a half-expanded Bottom Sheet
when viewed on a phone. This behavior can be changed to display it in a fully-expanded state. This can be achieved as follows:
@Composable
ListPicker(
stringItems = stringList,
data = ListPickerData(
label = "Expanded List Picker",
hint = "Select",
pickerTitle = "Choose Item",
showExpanded = true
)
)
Exit Dialog¶
When users make a selection and click on the Close button, an Exit Dialog
is displayed, which confirms whether the user wants to save or discard their selection. This behavior is enabled by default. The dialog title, message, and button text are all customizable. Application developers can also choose to not show the Exit Dialog
. All of this can be done using the ExitDialogData
Data Class
.
data class ExitDialogData(
val showDialog: Boolean = true,
val title: CharSequence? = null,
val message: CharSequence? = null,
val confirmButtonText: CharSequence? = null,
val dismissButtonText: CharSequence? = null
)
@Composable
ListPicker(
stringItems = stringList,
data = ListPickerData(
label = "Expanded List Picker",
hint = "Select",
pickerTitle = "Choose Item",
exitDialogData = ExitDialogData(showDialog = false)
)
)
Auto Save Single Selection List Picker¶
In the case of single selection, the List Picker
can be configured to save the selection and close the picker without the user having to click on the Apply button. When this is enabled, the footer can also optionally be hidden so that the Apply button is not displayed. This can be achieved as follows:
@Composable
ListPicker(
stringItems = stringList,
data = ListPickerData(
label = "Expanded List Picker",
hint = "Select",
pickerTitle = "Choose Item",
isSingleSelect = true,
autoSaveSelection = true,
footerData = FooterData(enabled = false)
)
)
Left to Right¶
The List Picker
allows you to position the selector (checkbox or radio) button on either left(start) or right(end) of the item view. This can be done as follows:
@Composable
ListPicker(
stringItems = stringList,
data = ListPickerData(
label = "Expanded List Picker",
hint = "Select",
pickerTitle = "Choose Item",
showSelectorOnStart = false
)
)