Pulsanti con icone

I pulsanti con icona mostrano le azioni che gli utenti possono intraprendere. I pulsanti con icona devono utilizzare un'icona con un significato chiaro e in genere rappresentano azioni comuni o utilizzate di frequente.

Esistono due tipi di pulsanti icona:

  • Predefinito: questi pulsanti possono aprire altri elementi, ad esempio un menu o una ricerca.
  • Attivazione/disattivazione: questi pulsanti possono rappresentare azioni binarie che possono essere attivate o disattivate, come "Preferito" o "Segnalibro".
5 pulsanti con icone diverse (impostazioni, altro e così via). Alcune sono piene, a indicare la selezione, e altre sono vuote.
Figura 1. Pulsanti con icone, alcuni dei quali sono pieni (per indicare la selezione) e con contorno.

Piattaforma API

Utilizza il componibile IconButton per implementare i pulsanti con icona standard. Per creare stili visivi diversi, come riempito, riempito tonale o con contorno, utilizza rispettivamente FilledIconButton, FilledTonalIconButton e OutlinedIconButton.

I parametri chiave per IconButton includono:

  • onClick: una funzione lambda che viene eseguita quando l'utente tocca il pulsante con icona.
  • enabled: un valore booleano che controlla lo stato di attivazione del pulsante. Quando false, il pulsante non risponde all'input dell'utente.
  • content: i contenuti componibili all'interno del pulsante, in genere un Icon.

Esempio di base: pulsante icona di attivazione/disattivazione

Questo esempio mostra come implementare un pulsante di attivazione/disattivazione con icona. Un pulsante con icona di attivazione/disattivazione cambia aspetto a seconda che sia selezionato o meno.

@Preview
@Composable
fun ToggleIconButtonExample() {
    // isToggled initial value should be read from a view model or persistent storage.
    var isToggled by rememberSaveable { mutableStateOf(false) }

    IconButton(
        onClick = { isToggled = !isToggled }
    ) {
        Icon(
            painter = if (isToggled) painterResource(R.drawable.favorite_filled) else painterResource(R.drawable.favorite),
            contentDescription = if (isToggled) "Selected icon button" else "Unselected icon button."
        )
    }
}

Punti chiave sul codice

  • Il componibile ToggleIconButtonExample definisce un IconButton attivabile/disattivabile.
    • mutableStateOf(false) crea un oggetto MutableState che contiene un valore booleano, inizialmente false. In questo modo, isToggled diventa un contenitore di stato, il che significa che Compose ricompone la UI ogni volta che il suo valore cambia.
    • rememberSaveable garantisce che lo stato di isToggled persista durante le modifiche alla configurazione, come la rotazione dello schermo.
  • La funzione lambda onClick di IconButton definisce il comportamento del pulsante quando viene fatto clic, attivando/disattivando lo stato tra true e false.
  • Il parametro painter del componibile Icon carica in modo condizionale un painterResource diverso in base allo stato isToggled. In questo modo, l'aspetto visivo dell'icona cambia.
    • Se isToggled è true, carica l'elemento drawable del cuore pieno.
    • Se isToggled è false, carica l'elemento drawable del cuore con contorno.
  • Anche l'elemento contentDescription di Icon viene aggiornato in base allo stato di isToggled per fornire informazioni sull'accessibilità appropriate.

Risultato

La seguente immagine mostra il pulsante di attivazione/disattivazione dello snippet precedente nello stato non selezionato:

Un pulsante di attivazione/disattivazione dei preferiti (un cuore) nello stato non selezionato (non riempito).
Figura 2. Un pulsante di attivazione/disattivazione "Preferito" non selezionato.

Esempio avanzato: azioni ripetute alla pressione

Questa sezione mostra come creare pulsanti con icone che attivano continuamente un'azione mentre l'utente li tiene premuti, anziché attivarla una sola volta per clic.

@Composable
fun MomentaryIconButton(
    unselectedImage: Int,
    selectedImage: Int,
    contentDescription: String,
    modifier: Modifier = Modifier,
    stepDelay: Long = 100L, // Minimum value is 1L milliseconds.
    onClick: () -> Unit
) {
    val interactionSource = remember { MutableInteractionSource() }
    val isPressed by interactionSource.collectIsPressedAsState()
    val pressedListener by rememberUpdatedState(onClick)

    LaunchedEffect(isPressed) {
        while (isPressed) {
            delay(stepDelay.coerceIn(1L, Long.MAX_VALUE))
            pressedListener()
        }
    }

    IconButton(
        modifier = modifier,
        onClick = onClick,
        interactionSource = interactionSource
    ) {
        Icon(
            painter = if (isPressed) painterResource(id = selectedImage) else painterResource(id = unselectedImage),
            contentDescription = contentDescription,
        )
    }
}

Punti chiave sul codice

  • MomentaryIconButton accetta un unselectedImage: Int, l'ID risorsa drawable per l'icona quando il pulsante non è premuto, e selectedImage: Int, l'ID risorsa drawable per l'icona quando il pulsante è premuto.
  • Utilizza un interactionSource per monitorare in modo specifico le interazioni di "pressione" dell'utente.
  • isPressed è true quando il pulsante viene premuto attivamente e false in caso contrario. Quando isPressed è true, LaunchedEffect entra in un loop.
    • All'interno di questo loop, utilizza un delay (con stepDelay) per creare pause tra le azioni di attivazione. coerceIn garantisce che il ritardo sia di almeno 1 ms per evitare loop infiniti.
    • pressedListener viene richiamato dopo ogni ritardo all'interno del loop. In questo modo, l'azione viene ripetuta.
  • pressedListener utilizza rememberUpdatedState per garantire che la funzione lambda onClick (l'azione da eseguire) sia sempre la più aggiornata dell'ultima composizione.
  • L'immagine visualizzata di Icon cambia a seconda che il pulsante sia premuto o meno.
    • Se isPressed è true, viene mostrato selectedImage.
    • In caso contrario, viene visualizzato unselectedImage.

Ora utilizza questo MomentaryIconButton in un esempio. Lo snippet seguente mostra due pulsanti con icona che controllano un contatore:

@Preview()
@Composable
fun MomentaryIconButtonExample() {
    var pressedCount by remember { mutableIntStateOf(0) }

    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically
    ) {
        MomentaryIconButton(
            unselectedImage = R.drawable.fast_rewind,
            selectedImage = R.drawable.fast_rewind_filled,
            stepDelay = 100L,
            onClick = { pressedCount -= 1 },
            contentDescription = "Decrease count button"
        )
        Spacer(modifier = Modifier)
        Text("advanced by $pressedCount frames")
        Spacer(modifier = Modifier)
        MomentaryIconButton(
            unselectedImage = R.drawable.fast_forward,
            selectedImage = R.drawable.fast_forward_filled,
            contentDescription = "Increase count button",
            stepDelay = 100L,
            onClick = { pressedCount += 1 }
        )
    }
}

Punti chiave sul codice

  • Il componibile MomentaryIconButtonExample mostra un Row contenente due istanze MomentaryIconButton e un componibile Text per creare una UI per incrementare e decrementare un contatore.
  • Mantiene una variabile di stato modificabile pressedCount utilizzando remember e mutableIntStateOf, inizializzata su 0. Quando pressedCount cambia, tutti i componibili che lo osservano (come il componibile Text) si ricompongono per riflettere il nuovo valore.
  • Il primo MomentaryIconButton diminuisce pressedCount quando viene selezionato o tenuto premuto.
  • La seconda MomentaryIconButton aumenta pressedCount quando viene selezionata o tenuta premuta.
  • Entrambi i pulsanti utilizzano un stepDelay di 100 millisecondi, il che significa che l'azione onClick viene ripetuta ogni 100 ms mentre un pulsante viene tenuto premuto.

Risultato

Il seguente video mostra la UI con i pulsanti icona e il contatore:

Figura 3. Un'interfaccia utente del contatore con due pulsanti icona (più e meno) che aumentano e diminuiscono il contatore.

Risorse aggiuntive