Skip to content

SuperSpinner

SuperSpinner is a dropdown selector component in Miuix that provides titles, summaries, and a list of options with icons and text. It supports click interaction and various display modes, commonly used in option settings with visual aids. This component is similar to SuperDropdown but offers richer functionality and interaction experience.

WARNING

SuperSpinner must be used within a Scaffold component!

Import

kotlin
import top.yukonga.miuix.kmp.extra.SuperSpinner
import top.yukonga.miuix.kmp.extra.SpinnerEntry

Basic Usage

The SuperSpinner component provides basic dropdown selector functionality:

kotlin
var selectedIndex by remember { mutableStateOf(0) }
val options = listOf(
    SpinnerEntry(title = "Option 1"),
    SpinnerEntry(title = "Option 2"),
    SpinnerEntry(title = "Option 3"),
)

Scaffold {
    SuperSpinner(
        title = "Dropdown Selector",
        items = options,
        selectedIndex = selectedIndex,
        onSelectedIndexChange = { selectedIndex = it }
    )
}

Options with Icons and Summaries

kotlin
// Create a rounded rectangle Painter
class RoundedRectanglePainter(
    private val cornerRadius: Dp = 6.dp
) : Painter() {
    override val intrinsicSize = Size.Unspecified

    override fun DrawScope.onDraw() {
        drawRoundRect(
            color = Color.White,
            size = Size(size.width, size.height),
            cornerRadius = CornerRadius(cornerRadius.toPx(), cornerRadius.toPx())
        )
    }
}

var selectedIndex by remember { mutableStateOf(0) }
val options = listOf(
    SpinnerEntry(
        icon = { Icon(RoundedRectanglePainter(), "Icon", Modifier.padding(end = 12.dp), Color(0xFFFF5B29)) },
        title = "Red Theme",
        summary = "Vibrant red"
    ),
    SpinnerEntry(
        icon = { Icon(RoundedRectanglePainter(), "Icon", Modifier.padding(end = 12.dp), Color(0xFF3482FF)) },
        title = "Blue Theme",
        summary = "Calm blue"
    ),
    SpinnerEntry(
        icon = { Icon(RoundedRectanglePainter(), "Icon", Modifier.padding(end = 12.dp), Color(0xFF36D167)) },
        title = "Green Theme",
        summary = "Fresh green"
    ),
    SpinnerEntry(
        icon = { Icon(RoundedRectanglePainter(), "Icon", Modifier.padding(end = 12.dp), Color(0xFFFFB21D)) }, 
        title = "Yellow Theme",
        summary = "Bright yellow"
    )
)

Scaffold {
    SuperSpinner(
        title = "Function Selection",
        summary = "Choose the action you want to perform",
        items = options,
        selectedIndex = selectedIndex,
        onSelectedIndexChange = { selectedIndex = it }
    )
}

Component States

Disabled State

kotlin
SuperSpinner(
    title = "Disabled Selector",
    summary = "This selector is currently unavailable",
    items = listOf(SpinnerEntry(title = "Option 1")),
    selectedIndex = 0,
    onSelectedIndexChange = {},
    enabled = false
)

Dialog Mode

Display Dropdown Menu in Dialog

kotlin
var selectedIndex by remember { mutableStateOf(0) }
val options = listOf(
    SpinnerEntry(title = "Option 1"),
    SpinnerEntry(title = "Option 2"),
    SpinnerEntry(title = "Option 3")
)

Scaffold {
    SuperSpinner(
        title = "Dialog Mode",
        dialogButtonString = "Cancel",
        items = options,
        selectedIndex = selectedIndex,
        onSelectedIndexChange = { selectedIndex = it }
    )
}

Properties

SuperSpinner Properties (Dropdown Mode)

Property NameTypeDescriptionDefault ValueRequired
itemsList<SpinnerEntry>Options list-Yes
selectedIndexIntCurrent selected item index-Yes
titleStringSelector title-Yes
titleColorBasicComponentColorsTitle text color configBasicComponentDefaults.titleColor()No
summaryString?Selector descriptionnullNo
summaryColorBasicComponentColorsSummary text color configBasicComponentDefaults.summaryColor()No
spinnerColorsSpinnerColorsColor configuration for spinnerSpinnerDefaults.spinnerColors()No
leftAction@Composable (() -> Unit)?Custom left contentnullNo
modifierModifierComponent modifierModifierNo
insideMarginPaddingValuesInternal content paddingBasicComponentDefaults.InsideMarginNo
maxHeightDp?Maximum dropdown heightnullNo
enabledBooleanInteractive statetrueNo
showValueBooleanShow current selected valuetrueNo
onClick(() -> Unit)?Additional click callbacknullNo
onSelectedIndexChange((Int) -> Unit)?Selection change callback-Yes

SuperSpinner Properties (Dialog Mode)

Property NameTypeDescriptionDefault ValueRequired
itemsList<SpinnerEntry>Options list-Yes
selectedIndexIntCurrent selected item index-Yes
titleStringSelector title-Yes
titleColorBasicComponentColorsTitle text color configBasicComponentDefaults.titleColor()No
summaryString?Selector descriptionnullNo
summaryColorBasicComponentColorsSummary text color configBasicComponentDefaults.summaryColor()No
spinnerColorsSpinnerColorsColor configuration for spinnerSpinnerDefaults.spinnerColors()No
leftAction@Composable (() -> Unit)?Custom left contentnullNo
dialogButtonStringStringDialog bottom button text-Yes
popupModifierModifierDialog popup modifierModifierNo
modifierModifierComponent modifierModifierNo
insideMarginPaddingValuesInternal content paddingBasicComponentDefaults.InsideMarginNo
enabledBooleanInteractive statetrueNo
showValueBooleanShow current selected valuetrueNo
onClick(() -> Unit)?Additional click callbacknullNo
onSelectedIndexChange((Int) -> Unit)?Selection change callback-Yes

SpinnerEntry Properties

Property NameTypeDescription
icon@Composable ((Modifier) -> Unit)?Option icon
titleString?Option title
summaryString?Option description

SpinnerColors Properties

Property NameTypeDescription
contentColorColorOption title color
summaryColorColorOption summary color
containerColorColorOption background color
selectedContentColorColorSelected item title color
selectedSummaryColorColorSelected item summary color
selectedContainerColorColorSelected item background color
selectedIndicatorColorColorSelected check icon color

Advanced Usage

Custom Colors

kotlin
var selectedIndex by remember { mutableStateOf(0) }
val options = listOf(
    SpinnerEntry(title = "Red"),
    SpinnerEntry(title = "Green"),
    SpinnerEntry(title = "Blue")
)

Scaffold {
    SuperSpinner(
        title = "Custom Colors",
        items = options,
        selectedIndex = selectedIndex,
        onSelectedIndexChange = { selectedIndex = it },
        spinnerColors = SpinnerDefaults.spinnerColors(
            contentColor = MiuixTheme.colorScheme.onSurface,
            summaryColor = MiuixTheme.colorScheme.onSurfaceVariantSummary,
            containerColor = MiuixTheme.colorScheme.surface,
            selectedContentColor = Color.Red,
            selectedSummaryColor = Color.Red,
            selectedContainerColor = Color.Red.copy(alpha = 0.12f),
            selectedIndicatorColor = Color.Red
        )
    )
}

Custom Left Content

kotlin
var selectedIndex by remember { mutableStateOf(0) }
val options = listOf(
    SpinnerEntry(title = "Red"),
    SpinnerEntry(title = "Green"),
    SpinnerEntry(title = "Blue")
)

Scaffold {
    SuperSpinner(
        title = "Custom Left Content",
        items = options,
        selectedIndex = selectedIndex,
        onSelectedIndexChange = { selectedIndex = it },
        leftAction = {
            Box(
                modifier = Modifier
                    .size(20.dp)
                    .background(
                        when (selectedIndex) {
                            0 -> Color.Red
                            1 -> Color.Green
                            else -> Color.Blue
                        },
                        shape = CircleShape
                    )
            )
            Spacer(Modifier.width(8.dp))
        }
    )
}

Limit Dropdown Menu Height

kotlin
var selectedIndex by remember { mutableStateOf(0) }
val options = List(20) { SpinnerEntry(title = "Option ${it + 1}") }

Scaffold {
    SuperSpinner(
        title = "Limit Height",
        items = options,
        selectedIndex = selectedIndex,
        onSelectedIndexChange = { selectedIndex = it },
        maxHeight = 300.dp // Limit dropdown menu maximum height to 300dp
    )
}

Hide Selected Value Display

kotlin
var selectedIndex by remember { mutableStateOf(0) }
val options = listOf(
    SpinnerEntry(title = "Option 1"),
    SpinnerEntry(title = "Option 2"),
    SpinnerEntry(title = "Option 3")
)

Scaffold {
    SuperSpinner(
        title = "Hide Selected Value",
        items = options,
        selectedIndex = selectedIndex,
        onSelectedIndexChange = { selectedIndex = it },
        showValue = false // Hide selected value display
    )
}

Use with Dialog

kotlin
// Create a rounded rectangle Painter
class RoundedRectanglePainter(
    private val cornerRadius: Dp = 6.dp
) : Painter() {
    override val intrinsicSize = Size.Unspecified

    override fun DrawScope.onDraw() {
        drawRoundRect(
            color = Color.White,
            size = Size(size.width, size.height),
            cornerRadius = CornerRadius(cornerRadius.toPx(), cornerRadius.toPx())
        )
    }
}

var showDialog = remember { mutableStateOf(false) }
var selectedIndex by remember { mutableStateOf(0) }
val colorOptions = listOf(
    SpinnerEntry(
        icon = { Icon(RoundedRectanglePainter(), "Icon", Modifier.padding(end = 12.dp), Color(0xFFFF5B29)) },
        title = "Red Theme",
        summary = "Vibrant red"
    ),
    SpinnerEntry(
        icon = { Icon(RoundedRectanglePainter(), "Icon", Modifier.padding(end = 12.dp), Color(0xFF3482FF)) },
        title = "Blue Theme",
        summary = "Calm blue"
    ),
    SpinnerEntry(
        icon = { Icon(RoundedRectanglePainter(), "Icon", Modifier.padding(end = 12.dp), Color(0xFF36D167)) },
        title = "Green Theme",
        summary = "Fresh green"
    ),
    SpinnerEntry(
        icon = { Icon(RoundedRectanglePainter(), "Icon", Modifier.padding(end = 12.dp), Color(0xFFFFB21D)) }, 
        title = "Yellow Theme",
        summary = "Bright yellow"
    )
)

Scaffold {
    SuperArrow(
        title = "Theme Color",
        onClick = { showDialog.value = true },
        holdDownState = showDialog.value
    )
    
    SuperDialog(
        title = "Theme Color Settings",
        show = showDialog,
        onDismissRequest = { showDialog.value = false } // Close dialog
    ) {
        Card {
            SuperSpinner(
                title = "Choose Theme Color",
                summary = "Select your preferred theme color",
                items = colorOptions,
                selectedIndex = selectedIndex,
                onSelectedIndexChange = { selectedIndex = it }
            )
        }
        
        Row(
            horizontalArrangement = Arrangement.SpaceBetween,
            modifier = Modifier.padding(top = 12.dp)
        ) {
            TextButton(
                text = "Cancel",
                onClick = { showDialog.value = false }, // Close dialog
                modifier = Modifier.weight(1f)
            )
            Spacer(Modifier.width(16.dp))
            TextButton(
                text = "Confirm",
                onClick = { showDialog.value = false }, // Close dialog
                modifier = Modifier.weight(1f),
                colors = ButtonDefaults.textButtonColorsPrimary() // Use theme color
            )
        }
    }
}

Released under the Apache-2.0 License