Pulsanti con icone

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

Esistono due tipi di pulsanti con icone:

  • Predefinito: questi pulsanti possono aprire altri elementi, ad esempio un menu o una ricerca.
  • Di attivazione/disattivazione: questi pulsanti possono rappresentare azioni binarie che possono essere attivate o disattivate, ad esempio "Preferito" o "Segnalibro".
5 pulsanti con icone diverse (impostazioni, altro e così via). Alcuni sono riempiti, a indicare che sono selezionati, mentre altri sono tratteggiati.
Figura 1. Pulsanti con icone, alcuni dei quali sono riempiti (a indicare la selezione) e delineati.

API surface

Utilizza il composable IconButton per implementare pulsanti con icone standard. Per creare diversi stili visivi, come riempito, tonalità riempita o con contorni, 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 dell'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 di attivazione/disattivazione con icona

Questo esempio mostra come implementare un pulsante con icona di attivazione/disattivazione. L'aspetto di un pulsante con icona di attivazione/disattivazione cambia 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 del 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 detentore dello stato, il che significa che Compose ricomporrà l'interfaccia utente ogni volta che il relativo valore cambia.
    • rememberSaveable garantisce che lo stato isToggled persista anche in seguito alle modifiche di configurazione, come la rotazione dello schermo.
  • Il 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 composable Icon carica condizionatamente un painterResource diverso in base allo stato isToggled. In questo modo, l'aspetto dell'icona cambia.
    • Se isToggled è true, viene caricato il disegno del cuore pieno.
    • Se isToggled è false, viene caricato il disegno del cuore con il contorno.
  • Anche il contentDescription del Icon si aggiorna in base allo stato del isToggled per fornire informazioni sull'accessibilità appropriate.

Risultato

L'immagine seguente mostra il pulsante dell'icona di attivazione/disattivazione dello snippet precedente nel suo stato non selezionato:

Un pulsante di attivazione/disattivazione dell'icona del preferito (un cuore) nello stato non selezionato (non compilato).
Figura 2. Un pulsante di attivazione/disattivazione dell'icona "Preferito" non selezionato.

Esempio avanzato: azioni ripetute con pressione

Questa sezione mostra come creare pulsanti con icone che attivano continuamente un'azione mentre l'utente li preme e li tiene premuti, anziché attivarsi solo una 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 del codice

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

A questo punto, utilizza MomentaryIconButton in un esempio. Lo snippet seguente mostra due pulsanti con icone 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 del codice

  • Il composable MomentaryIconButtonExample mostra un Row contenente due MomentaryIconButton e un composable Text per creare un'interfaccia utente per incrementare e decrementare un contatore.
  • Mantiene una variabile di stato mutabile pressedCount utilizzando remember e mutableIntStateOf, inizializzata a 0. Quando pressedCount cambia, tutti i composabili che lo osservano (come il composable Text) si ricompono per riflettere il nuovo valore.
  • Il primo MomentaryIconButton diminuisce pressedCount quando viene fatto clic o premuto.
  • Il secondo MomentaryIconButton aumenta pressedCount quando viene premuto o tenuto premuto.
  • Entrambi i pulsanti utilizzano un stepDelay di 100 millisecondi, il che significa che l'azione onClick si ripete ogni 100 ms mentre un pulsante è premuto.

Risultato

Il video seguente mostra l'interfaccia utente con i pulsanti delle icone e il contatore:

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

Risorse aggiuntive