Configurare i campi di testo

TextField consente agli utenti di inserire e modificare il testo. Esistono due tipi di campi di testo che puoi utilizzare: campi di testo basati sullo stato e campi di testo basati sul valore. Seleziona il tipo per cui vuoi visualizzare i contenuti:

Ti consigliamo di utilizzare i campi di testo basati sullo stato, in quanto forniscono un approccio più completo e affidabile alla gestione dello stato di un TextField. La seguente tabella mostra le differenze tra questi tipi di campi di testo e include i principali vantaggi offerti dai campi di testo basati sullo stato:

Funzionalità

Campi di testo basati sul valore

Campi di testo basati sullo stato

Prestazione basata sullo stato

Gestione dello stato

Aggiorna lo stato del campo di testo con il callback onValueChange. È tua responsabilità aggiornare il value nel tuo stato in base alle modifiche segnalate da onValueChange.

Utilizza in modo esplicito un oggetto TextFieldState per gestire lo stato dell'input di testo (valore, selezione, composizione). Questo stato può essere ricordato e condiviso.

  • Il callback onValueChange è stato rimosso, il che ti impedisce di introdurre comportamenti asincroni.
  • Lo stato sopravvive alla ricomposizione, alla configurazione e all'interruzione del processo.

Trasformazione visiva

Utilizza VisualTransformation per modificare l'aspetto del testo visualizzato. In genere, la formattazione di input e output viene gestita in un unico passaggio.

Utilizza InputTransformation per modificare l'input dell'utente prima che venga salvato nello stato e OutputTransformation per formattare il contenuto del campo di testo senza modificare i dati di stato sottostanti.

  • Non è più necessario fornire la mappatura dell'offset tra il testo non elaborato originale e il testo trasformato con OutputTransformation.

Limiti di righe

Accetta singleLine: Boolean, maxLines: Int e minLines: Int per controllare il numero di righe.

Utilizza lineLimits: TextFieldLineLimits per configurare il numero minimo e massimo di righe che il campo di testo può occupare.

  • Elimina l'ambiguità durante la configurazione dei limiti di righe fornendo un parametro lineLimits di tipo TextFieldLineLimits.

Campo di testo sicuro

N/D

SecureTextField è un componente componibile basato su campi di testo basati sullo stato per scrivere un campo password.

  • Consente di ottimizzare la sicurezza in modo trasparente e viene fornito con un'interfaccia utente predefinita con textObfuscationMode.

Questa pagina descrive come implementare TextField, applicare lo stile all'input TextField e configurare altre opzioni TextField, come le opzioni della tastiera e la trasformazione visiva dell'input dell'utente.

Scegli l'implementazione di TextField

Esistono due livelli di implementazione di TextField:

  1. TextField è l'implementazione di Material Design. Ti consigliamo di scegliere questa implementazione perché segue le linee guida di Material Design:
  2. BasicTextField consente agli utenti di modificare il testo tramite tastiera hardware o software, ma non fornisce decorazioni come suggerimenti o segnaposto.

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

Un campo di testo modificabile contenente la parola

OutlinedTextField(
    state = rememberTextFieldState(),
    label = { Text("Label") }
)

Un campo di testo modificabile, con un bordo e un'etichetta viola.

Stile TextField

TextField e BasicTextField condividono molti parametri comuni per la personalizzazione. L'elenco completo per TextField è disponibile nel codice sorgente di TextField. Di seguito è riportato un elenco non esaustivo di alcuni dei parametri utili:

  • textStyle
  • lineLimits

TextField(
    state = rememberTextFieldState("Hello\nWorld\nInvisible"),
    lineLimits = TextFieldLineLimits.MultiLine(maxHeightInLines = 2),
    placeholder = { Text("") },
    textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
    label = { Text("Enter text") },
    modifier = Modifier.padding(20.dp)
)

Un TextField multilinea, con due righe modificabili più l'etichetta

Ti consigliamo di utilizzare TextField anziché BasicTextField quando il design richiede un TextField o OutlinedTextField Material. Tuttavia, BasicTextField deve essere utilizzato quando si creano design che non richiedono le decorazioni della specifica Material.

Configurare i limiti di righe

I composable TextField supportano lo scorrimento lungo un solo asse. Il comportamento di scorrimento è determinato dal parametro lineLimits. TextFields configurato per lo scorrimento orizzontale di una singola riga, mentre TextFields multiriga scorre verticalmente.

Utilizza TextFieldLineLimits per scegliere la configurazione di linea appropriata per il tuo TextField:

TextField(
    state = rememberTextFieldState(),
    lineLimits = TextFieldLineLimits.SingleLine
)

Un campo di testo a una sola riga con il testo

La configurazione SingleLine ha le seguenti caratteristiche:

  • Il testo non va mai a capo e non consente nuove righe.
  • TextField ha sempre un'altezza fissa.
  • Se il testo non rientra, scorre orizzontalmente.

TextField(
    state = rememberTextFieldState("Hello\nWorld\nHello\nWorld"),
    lineLimits = TextFieldLineLimits.MultiLine(1, 4)
)

Un campo di testo multilinea con il testo

La configurazione MultiLine ha le seguenti caratteristiche:

  • Accetta due parametri: minHeightInLines e maxHeightInLines.
  • Il campo di testo è alto almeno minHeightInLines.
  • Se il testo va in overflow, verrà eseguito il wrapping.
  • Se il testo richiede più righe, il campo si espande fino a raggiungere un'altezza di maxHeightInLines e scorre verticalmente.

Input di stile con l'API Brush

Puoi utilizzare l'API Brush per uno stile più avanzato nel tuo TextField. La sezione seguente descrive come utilizzare un pennello per aggiungere una sfumatura colorata all'input TextField.

Per saperne di più sull'utilizzo dell'API Brush per applicare stili al testo, consulta Attivare lo stile avanzato con l'API Brush.

Implementare sfumature colorate utilizzando TextStyle

Per implementare un gradiente colorato durante la digitazione all'interno di un TextField, imposta il pennello che preferisci come TextStyle per il TextField. In questo esempio, utilizziamo un pennello integrato con un linearGradient per visualizzare l'effetto sfumato arcobaleno mentre il testo viene digitato in TextField.

val brush = remember {
    Brush.linearGradient(
        colors = listOf(Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Magenta)
    )
}
TextField(
    state = rememberTextFieldState(), textStyle = TextStyle(brush = brush)
)

Utilizzo di buildAnnotatedString e SpanStyle, insieme a linearGradient, per personalizzare solo una parte di testo.
Figura 1. Un effetto gradiente arcobaleno per i contenuti di TextField.

Gestire lo stato del campo di testo

TextField utilizza una classe di gestione dello stato dedicata chiamata TextFieldState per i suoi contenuti e la selezione corrente. TextFieldState è progettato per essere caricato ovunque si adatti alla tua architettura. TextFieldState fornisce due proprietà principali:

  • initialText: contenuti di TextField.
  • initialSelection: indica la posizione attuale del cursore o della selezione.

Ciò che differenzia TextFieldState da altri approcci, come il callback onValueChange, è che TextFieldState incapsula completamente l'intero flusso di input. Ciò include l'utilizzo delle strutture di dati di supporto corrette, l'incorporamento di filtri e formattatori, nonché la sincronizzazione di tutte le modifiche provenienti da fonti diverse.

Puoi utilizzare TextFieldState() per sollevare lo stato in TextField. Per questo, ti consigliamo di utilizzare la funzione rememberTextFieldState(). rememberTextFieldState() crea l'istanza TextFieldState nel tuo componente componibile, garantisce che l'oggetto stato venga ricordato e fornisce funzionalità integrate di salvataggio e ripristino:

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

rememberTextFieldState può avere un parametro vuoto o un valore iniziale passato per rappresentare il valore del testo all'inizializzazione. Se viene passato un valore diverso in una ricomposizione successiva, il valore dello stato non viene aggiornato. Per aggiornare lo stato dopo l'inizializzazione, chiama i metodi di modifica su TextFieldState.

TextField(
    state = rememberTextFieldState(initialText = "Username"),
    lineLimits = TextFieldLineLimits.SingleLine,
)

Un TextField con il testo Nome utente visualizzato all'interno del campo di testo.
Figura 2. TextField con "Nome utente" come testo iniziale.

Modificare il testo con TextFieldBuffer

Un TextFieldBuffer funge da contenitore di testo modificabile, simile per funzione a un StringBuilder. Contiene sia il contenuto di testo sia le informazioni sulla selezione corrente.

Spesso si incontra TextFieldBuffer come ambito del ricevitore in funzioni come TextFieldState.edit, InputTransformation.transformInput o OutputTransformation.transformOutput. In queste funzioni, puoi leggere o aggiornare TextFieldBuffer in base alle tue esigenze. Successivamente, queste modifiche vengono eseguite in TextFieldState o passate alla pipeline di rendering nel caso di OutputTransformation.

Puoi utilizzare le funzioni di modifica standard come append, insert, replace o delete per modificare i contenuti del buffer. Per modificare lo stato di selezione, imposta direttamente la variabile selection: TextRange o utilizza funzioni di utilità come placeCursorAtEnd o selectAll. La selezione stessa è rappresentata da un TextRange, dove l'indice iniziale è inclusivo e l'indice finale è esclusivo. Un TextRange con valori di inizio e fine identici, ad esempio (3, 3), indica una posizione del cursore senza caratteri attualmente selezionati.

val phoneNumberState = rememberTextFieldState()

LaunchedEffect(phoneNumberState) {
    phoneNumberState.edit { // TextFieldBuffer scope
        append("123456789")
    }
}

TextField(
    state = phoneNumberState,
    inputTransformation = InputTransformation { // TextFieldBuffer scope
        if (asCharSequence().isDigitsOnly()) {
            revertAllChanges()
        }
    },
    outputTransformation = OutputTransformation {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
)

Modifica il testo in TextFieldState

Esistono diversi metodi che consentono di modificare lo stato direttamente tramite la variabile di stato:

  • edit: consente di modificare i contenuti dello stato e fornisce funzioni TextFieldBuffer per poter utilizzare metodi come insert, replace, append e altri ancora.

    val usernameState = rememberTextFieldState("I love Android")
    // textFieldState.text : I love Android
    // textFieldState.selection: TextRange(14, 14)
    usernameState.edit { insert(14, "!") }
    // textFieldState.text : I love Android!
    // textFieldState.selection: TextRange(15, 15)
    usernameState.edit { replace(7, 14, "Compose") }
    // textFieldState.text : I love Compose!
    // textFieldState.selection: TextRange(15, 15)
    usernameState.edit { append("!!!") }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(18, 18)
    usernameState.edit { selectAll() }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(0, 18)

  • setTextAndPlaceCursorAtEnd: cancella il testo corrente, lo sostituisce con il testo fornito e posiziona il cursore alla fine.

    usernameState.setTextAndPlaceCursorAtEnd("I really love Android")
    // textFieldState.text : I really love Android
    // textFieldState.selection : TextRange(21, 21)

  • clearText: cancella tutto il testo.

    usernameState.clearText()
    // textFieldState.text :
    // textFieldState.selection : TextRange(0, 0)

Per altre funzioni TextFieldState, consulta il riferimento TextFieldState.

Modificare l'input utente

Le sezioni seguenti descrivono come modificare l'input dell'utente. La trasformazione dell'input consente di filtrare l'input TextField mentre l'utente digita, mentre la trasformazione dell'output formatta l'input dell'utente prima che venga visualizzato sullo schermo.

Filtrare l'input dell'utente con le trasformazioni dell'input

Una trasformazione dell'input consente di filtrare l'input dell'utente. Ad esempio, se il tuo TextField accetta un numero di telefono americano, vuoi accettare solo 10 cifre. I risultati di InputTransformation vengono salvati in TextFieldState.

Sono disponibili filtri integrati per i casi d'uso comuni di InputTransformation. Per limitare la durata, chiama il numero InputTransformation.maxLength():

TextField(
    state = rememberTextFieldState(),
    lineLimits = TextFieldLineLimits.SingleLine,
    inputTransformation = InputTransformation.maxLength(10)
)

Trasformazioni di input personalizzate

InputTransformation è un'interfaccia di una singola funzione. Quando implementi il tuo InputTransformation personalizzato, devi eseguire l'override di TextFieldBuffer.transformInput:

class CustomInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
    }
}

Per un numero di telefono, aggiungi una trasformazione dell'input personalizzata che consenta di digitare solo cifre nel TextField:

class DigitOnlyInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
        if (!TextUtils.isDigitsOnly(asCharSequence())) {
            revertAllChanges()
        }
    }
}

Trasformazioni dell'input a catena

Per aggiungere più filtri all'input di testo, concatenali utilizzando la funzione di estensione then.InputTransformation I filtri vengono eseguiti in sequenza. Come best practice, applica prima i filtri più selettivi per evitare trasformazioni non necessarie sui dati che alla fine verranno filtrati.

TextField(
    state = rememberTextFieldState(),
    inputTransformation = InputTransformation.maxLength(6)
        .then(CustomInputTransformation()),
)

Dopo aver aggiunto le trasformazioni dell'input, l'input TextField accetta un massimo di 10 cifre.

Formatta l'input prima che venga visualizzato

OutputTransformation consente di formattare l'input dell'utente prima che venga visualizzato sullo schermo. A differenza di InputTransformation, la formattazione eseguita tramite OutputTransformation non viene salvata in TextFieldState. Partendo dall'esempio precedente del numero di telefono, devi aggiungere parentesi e trattini nei punti appropriati:

Un numero di telefono americano, formattato correttamente con parentesi, trattini e indici corrispondenti.
Figura 3. Un numero di telefono americano con formattazione corretta e indici corrispondenti.

Questo è il modo aggiornato di gestire i VisualTransformation nei TextField basati sul valore, con la differenza principale che non devi calcolare le mappature degli offset.

OutputTransformation è un'interfaccia con un singolo metodo astratto. Per implementare un OutputTransformation personalizzato, devi eseguire l'override del metodo transformOutput:

class CustomOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
    }
}

Per formattare un numero di telefono, aggiungi una parentesi aperta all'indice 0, una parentesi chiusa all'indice 4 e un trattino all'indice 8 al tuo OutputTransformation:

class PhoneNumberOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
}

Poi, aggiungi il tuo OutputTransformation a TextField:

TextField(
    state = rememberTextFieldState(),
    outputTransformation = PhoneNumberOutputTransformation()
)

Come interagiscono le trasformazioni

Il seguente diagramma mostra il flusso dall'input di testo alla trasformazione in output:

Una visualizzazione di come l'input di testo viene trasformato prima di diventare output di testo.
Figura 4. Un diagramma che mostra come l'input di testo viene trasformato prima di diventare output di testo.
  1. L'input viene ricevuto dalla sorgente di input.
  2. L'input viene filtrato tramite un InputTransformation, che viene salvato in TextFieldState.
  3. L'input viene passato tramite un OutputTransformation per la formattazione.
  4. L'input viene presentato in TextField.

Impostare le opzioni della tastiera

TextField ti consente di impostare le opzioni di configurazione della tastiera, ad esempio il layout della tastiera, o di attivare la correzione automatica se è supportata dalla tastiera. Alcune opzioni potrebbero non essere garantite se la tastiera software non è conforme alle opzioni fornite qui. Ecco l'elenco delle opzioni di tastiera supportate:

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

La classe KeyboardOptions ora include un nuovo parametro booleano, showKeyboardOnFocus, che utilizzi specificamente per i componenti TextField integrati con TextFieldState. Questa opzione regola il comportamento della tastiera software quando TextField acquisisce lo stato attivo con mezzi diversi dall'interazione diretta dell'utente (ad esempio, a livello di programmazione).

Quando KeyboardOptions.showKeyboardOnFocus è impostato su true, la tastiera software non viene visualizzata automaticamente se TextField acquisisce il focus indirettamente. In questi casi, l'utente deve toccare esplicitamente il TextField per visualizzare la tastiera.

Definisci la logica di interazione della tastiera

Il pulsante di azione sulla tastiera software di Android consente risposte interattive all'interno dell'applicazione. Per ulteriori informazioni sulla configurazione del pulsante di azione, consulta la sezione Impostare le opzioni della tastiera.

Un pulsante di azione della tastiera su schermo (un'icona a forma di segno di spunta) cerchiato in rosso.
Figura 5. Pulsante di azione della tastiera software.

Per definire cosa succede quando un utente tocca questo pulsante di azione, utilizza il parametro onKeyboardAction. Questo parametro accetta un'interfaccia funzionale facoltativa denominata KeyboardActionHandler. L'interfaccia KeyboardActionHandler contiene un unico metodo, onKeyboardAction(performDefaultAction: () -> Unit). Fornendo un'implementazione per questo metodo onKeyboardAction, puoi introdurre una logica personalizzata che viene eseguita quando un utente preme il pulsante di azione della tastiera.

Diversi tipi di azioni da tastiera standard sono dotati di comportamenti predefiniti integrati. Ad esempio, se selezioni ImeAction.Next o ImeAction.Previous come tipo di azione, lo stato attivo si sposta per impostazione predefinita sul campo di input successivo o precedente, rispettivamente. Analogamente, un pulsante di azione impostato su ImeAction.Done in genere chiude la tastiera software. Queste funzionalità predefinite vengono eseguite automaticamente e non richiedono di fornire un KeyboardActionHandler.

Oltre a queste azioni predefinite, puoi implementare un comportamento personalizzato. Quando fornisci il tuo KeyboardActionHandler, il relativo metodo onKeyboardAction riceve una funzione performDefaultAction. Puoi chiamare questa funzione performDefaultAction() in qualsiasi punto della logica personalizzata per attivare anche il comportamento predefinito standard associato all'azione IME corrente.

TextField(
    state = textFieldViewModel.usernameState,
    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
    onKeyboardAction = { performDefaultAction ->
        textFieldViewModel.validateUsername()
        performDefaultAction()
    }
)

Questo snippet illustra un caso d'uso comune in una schermata di registrazione con un campo per il nome utente. Per questo campo, ImeAction.Next è selezionato per il pulsante di azione della tastiera. Questa scelta consente di passare rapidamente e senza problemi al campo della password successivo.

Oltre a questa navigazione standard, è necessario avviare una procedura di convalida in background per il nome utente mentre l'utente procede all'inserimento della password. Per garantire che il comportamento di cambio di messa a fuoco predefinito inerente a ImeAction.Next venga mantenuto insieme a questa logica di convalida personalizzata, viene richiamata la funzione performDefaultAction(). La chiamata di performDefaultAction() attiva implicitamente il sistema di gestione della messa a fuoco sottostante per spostare lo stato attivo sul successivo elemento dell'interfaccia utente appropriato, preservando il flusso di navigazione previsto.

Creare un campo password sicuro

SecureTextField è un componente componibile basato su campi di testo basati sullo stato per scrivere un campo password. Ti consigliamo di utilizzare SecureTextField per creare campi di testo per le password, in quanto nasconde l'input di caratteri per impostazione predefinita e disattiva le azioni di taglio e copia.

SecureTextField ha un textObfuscationMode, che controlla il modo in cui l'utente vede l'input dei caratteri. textObfuscationMode ha le seguenti opzioni:

  • Hidden: nasconde tutti gli input. Comportamento predefinito sulle piattaforme desktop.

  • Visible: mostra tutti gli input.

  • RevealLastTyped: nasconde tutto l'input tranne l'ultimo carattere. Comportamento predefinito sui dispositivi mobili.

Risorse aggiuntive