Skip to content

Dialog List

This shows a dialog with a list of items. Rendering, selection mode and more is adjustable.

Check out the composable and it's documentation in the code snipplet below.

Generally following can be adjusted:

  • list of items or loading list items asynchronously
  • single selection / multi selection / clickable
  • optional dividers
  • filter and search functionality
  • custom items

Composable#

There are 2 ways to show a list, one by providing a list of items and one by providing an asynchronous item loader function.

/**
 * Shows a dialog with a list and an optional filter option
 *
 * consider the overload with a lambda for the items parameter if items should be loaded lazily
 *
 *  
 *
 * **Basic Parameters:** all params not described here are derived from [Dialog], check it out for more details
 *
 * @param items the list items
 * @param itemIdProvider the items to id lambda that is used to store selected item ids
 * @param itemContents the [DialogList.ItemContents] holding composables to customise the rendering of the list items - use [DialogList.ItemDefaultContent] or [DialogList.ItemContents] if you want to completely customise the items
 * @param selectionMode the [DialogList.SelectionMode]
 * @param divider if true, a divider is shown between the list items
 * @param description a custom text that will be shown as description at the top of the dialog
 * @param filter the [DialogList.Filter] - if it is null, filtering is disabled
 */
@Composable
fun <T> DialogList(
    state: DialogState,
    // Custom - Required
    items: List<T>,
    itemIdProvider: (item: T) -> Int,
    itemContents: DialogList.ItemContents<T>,
    selectionMode: DialogList.SelectionMode<T>,
    // Custom - Optional
    divider: Boolean = false,
    description: String = "",
    filter: DialogList.Filter<T>? = null,
    // Base Dialog - Optional
    title: (@Composable () -> Unit)? = null,
    icon: (@Composable () -> Unit)? = null,
    style: ComposeDialogStyle = DialogDefaults.defaultDialogStyle(),
    buttons: DialogButtons = DialogDefaults.buttons(),
    options: Options = Options(),
    onEvent: (event: DialogEvent) -> Unit = {}
)
/**
 * Shows a dialog with a list and an optional filter option
 *
 * consider the overload with a list if the items are just a simple list of items
 *
 * &nbsp;
 *
 * **Basic Parameters:** all params not described here are derived from [Dialog], check it out for more details
 *
 * @param itemsLoader the lambda that will return the items for this dialog
 * @param itemIdProvider the items to id lambda that is used to store selected item ids
 * @param itemContents the [DialogList.ItemContents] holding composables to customise the rendering of the list items - use [DialogList.ItemDefaultContent] or [DialogList.ItemContents] if you want to completely customise the items
 * @param selectionMode the [DialogList.SelectionMode]
 * @param itemSaver the saver for the list items - if no itemSaver is provided, data won't be remembered as saveable and will be reloaded on recomposition (e.g. screen rotation)
 * @param loadingIndicator the composable that will be shown while items are loaded
 * @param divider if true, a divider is shown between the list items
 * @param description a custom text that will be shown as description at the top of the dialog
 * @param filter the [DialogList.Filter] - if it is null, filtering is disabled
 */
@Composable
fun <T> DialogList(
    state: DialogState,
    // Custom - Required
    itemsLoader: suspend () -> List<T>,
    itemIdProvider: (item: T) -> Int,
    itemContents: DialogList.ItemContents<T>,
    selectionMode: DialogList.SelectionMode<T>,
    // Custom - Optional
    itemSaver: Saver<MutableState<List<T>>, out Any>? = null,
    loadingIndicator: @Composable () -> Unit = {
        Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
            CircularProgressIndicator()
        }
    },
    divider: Boolean = false,
    description: String = "",
    filter: DialogList.Filter<T>? = null,
    // Base Dialog - Optional
    title: (@Composable () -> Unit)? = null,
    icon: (@Composable () -> Unit)? = null,
    style: ComposeDialogStyle = DialogDefaults.defaultDialogStyle(),
    buttons: DialogButtons = DialogDefaults.buttons(),
    options: Options = Options(),
    onEvent: (event: DialogEvent) -> Unit = {}
)

Example#

val selected = remember { mutableStateOf<Int?>(null) }
val items = List(100) { "Item $it" }
DialogList(
    style = style,
    title = { Text("List Dialog") },
    icon = getIcon,
    description = "Some optional description",
    state = dialog,
    items = items,
    itemIdProvider = { items.indexOf(it) },
    selectionMode = DialogList.SelectionMode.SingleSelect(
        selected = selected,
        selectOnRadioButtonClickOnly = false
    ),
    itemContents = DialogList.ItemDefaultContent(
        text = { it }
    ),
    onEvent = {
        if (it is DialogEvent.Button && it.button == DialogButtonType.Positive) {
            infos.add("Selected list value: ${selected.value?.let { "Index = $it | Item = ${items[it]}" }}")
        } else {
            infos.add("Event $it")
        }
    }
)

Screenshots#

Screenshot Screenshot Screenshot Screenshot
Screenshot Screenshot Screenshot