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
import top.yukonga.miuix.kmp.extra.SpinnerMode

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
)

Display Modes

SuperSpinner supports different display modes:

Normal Mode (Adaptive to Click Position)

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 = "Normal Mode",
        items = options,
        selectedIndex = selectedIndex,
        onSelectedIndexChange = { selectedIndex = it },
        mode = SpinnerMode.Normal // Default value
    )
}

Always on Right Mode

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 = "Always on Right Mode",
        items = options,
        selectedIndex = selectedIndex,
        onSelectedIndexChange = { selectedIndex = it },
        mode = SpinnerMode.AlwaysOnRight // Always on right 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
leftAction@Composable (() -> Unit)?Custom left contentnullNo
modeSpinnerModeDisplay modeSpinnerMode.NormalNo
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
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

Advanced Usage

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