Configura campos de texto

TextField permite a los usuarios ingresar y modificar texto. Existen dos tipos de campos de texto que puedes usar: campos de texto basados en el estado y campos de texto basados en el valor. Selecciona el tipo para el que quieres mostrar contenido:

Te recomendamos que uses campos de texto basados en el estado, ya que proporcionan un enfoque más completo y confiable para administrar el estado de un TextField. En la siguiente tabla, se describen las diferencias entre estos tipos de campos de texto y se incluyen las ventajas clave que ofrecen los campos de texto basados en el estado:

Función

Campos de texto basados en valores

Campos de texto basados en el estado

Beneficio estatal

Administración de estado

Actualiza el estado del campo de texto con la devolución de llamada onValueChange. Eres responsable de actualizar el value en tu propio estado según los cambios que informa onValueChange.

Usa de forma explícita un objeto TextFieldState para administrar el estado de entrada de texto (valor, selección y composición). Este estado se puede recordar y compartir.

  • Se quitó la devolución de llamada onValueChange, lo que evita que introduzcas comportamientos asíncronos.
  • El estado sobrevive a la recomposición, la configuración y el cierre del proceso.

Transformación visual

Usa VisualTransformation para modificar cómo aparece el texto que se muestra. Por lo general, esto controla el formato de entrada y salida en un solo paso.

Usa InputTransformation para modificar la entrada del usuario antes de que se confirme en el estado y OutputTransformation para dar formato al contenido del campo de texto sin cambiar los datos de estado subyacentes.

  • Ya no necesitas proporcionar la asignación de compensación entre el texto sin procesar original y el texto transformado con OutputTransformation.

Límites de líneas

Acepta singleLine: Boolean, maxLines: Int y minLines: Int para controlar la cantidad de líneas.

Usa lineLimits: TextFieldLineLimits para configurar la cantidad mínima y máxima de líneas que puede ocupar el campo de texto.

  • Quita la ambigüedad cuando se configuran los límites de líneas proporcionando un parámetro lineLimits de tipo TextFieldLineLimits.

Campo de texto seguro

N/A

SecureTextField es un elemento componible que se basa en campos de texto basados en el estado para escribir un campo de contraseña.

  • Te permite optimizar la seguridad de forma interna y viene con una IU predefinida con textObfuscationMode.

En esta página, se describe cómo puedes implementar TextField, aplicar diseño a la entrada de TextField y configurar otras opciones de TextField, como las opciones de teclado y la transformación visual de la entrada del usuario.

Elige la implementación de TextField

Hay dos niveles de implementación de TextField:

  1. TextField es la implementación de Material Design. Te recomendamos que elijas esta implementación, ya que sigue los lineamientos de Material Design:
    • El estilo predeterminado está relleno.
    • OutlinedTextField es la versión de estilo de contorno.
  2. BasicTextField permite a los usuarios editar texto con el teclado en pantalla o físico, pero no proporciona decoraciones como sugerencias o marcadores de posición.

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

Un campo de texto editable que contiene la palabra

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

Campo de texto editable, con la etiqueta y un borde púrpura.

Estilo TextField

TextField y BasicTextField comparten muchos parámetros comunes de personalización. La lista completa para TextField está disponible en el código fuente de TextField. Esta es una lista no exhaustiva de algunos de los parámetros útiles:

  • 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 de varias líneas, con dos líneas editables más la etiqueta

Recomendamos usar TextField en lugar de BasicTextField cuando el diseño llame a un campo TextField o OutlinedTextField de Material. Sin embargo, BasicTextField debe usarse cuando se crean diseños que no necesitan las decoraciones de la especificación de Material.

Configura los límites de líneas

Los elementos componibles TextField admiten el desplazamiento a lo largo de un solo eje. El comportamiento de desplazamiento se determina con el parámetro lineLimits. Los TextField configurados para una sola línea se desplazan de forma horizontal, mientras que los TextField de varias líneas se desplazan de forma vertical.

Usa TextFieldLineLimits para elegir la configuración de línea adecuada para tu TextField:

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

Un campo de texto de una sola línea con el texto

La configuración de SingleLine tiene las siguientes características:

  • El texto nunca se ajusta y no permite líneas nuevas.
  • TextField siempre tiene una altura fija.
  • Si el texto se desborda, se desplaza de forma horizontal.

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

Un campo de texto de varias líneas con el texto

La configuración de MultiLine tiene las siguientes características:

  • Acepta dos parámetros: minHeightInLines y maxHeightInLines.
  • El campo de texto tiene al menos minHeightInLines de altura.
  • Si el texto se desborda, se ajustará.
  • Si el texto requiere más líneas, el campo crece hasta alcanzar una altura de maxHeightInLines y se desplaza verticalmente.

Cómo aplicar diseño a la entrada con la API de Brush

Puedes usar la API de Brush para aplicar un diseño más avanzado en tu TextField. En la siguiente sección, se describe cómo puedes usar un Brush para agregar un gradiente de color a la entrada de TextField.

Para obtener más información sobre cómo usar la API de Brush para aplicar diseño al texto, consulta Habilita el diseño avanzado con la API de Brush.

Implementa gradientes de color con TextStyle

Para implementar un gradiente de color mientras escribes en un TextField, establece el pincel que elijas como un TextStyle para tu TextField. En este ejemplo, usamos un pincel integrado con un linearGradient para ver el efecto de gradiente de arcoíris a medida que se escribe texto en el 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)
)

Texto que se escribe en un campo de texto, con un efecto de gradiente de arcoíris.
Figura 1: Un efecto de degradado de arcoíris para el contenido de TextField.

Administra el estado del campo de texto

TextField usa una clase de contenedor de estado dedicada llamada TextFieldState para su contenido y selección. TextFieldState está diseñado para elevarse donde sea que se ajuste a tu arquitectura. TextFieldState proporciona 2 propiedades principales:

  • initialText: Es el contenido de TextField.
  • initialSelection: Indica dónde se encuentra el cursor o la selección.

Lo que diferencia a TextFieldState de otros enfoques, como la devolución de llamada onValueChange, es que TextFieldState encapsula por completo todo el flujo de entrada. Esto incluye usar las estructuras de datos de respaldo correctas, intercalar filtros y formateadores, y también sincronizar todas las ediciones provenientes de diferentes fuentes.

Puedes usar TextFieldState() para elevar el estado en TextField. Para ello, te recomendamos que uses la función rememberTextFieldState(). rememberTextFieldState() crea la instancia de TextFieldState en tu elemento componible, se asegura de que se recuerde el objeto de estado y proporciona funciones integradas para guardar y restablecer:

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

rememberTextFieldState puede tener un parámetro en blanco o un valor inicial que se pasa para representar el valor del texto en la inicialización. Si se pasa un valor diferente en una recomposición posterior, el valor del estado no se actualiza. Para actualizar el estado después de que se inicialice, llama a los métodos de edición en TextFieldState.

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

Un TextField con el texto Username que aparece dentro del campo de texto.
Figura 2: TextField con "Nombre de usuario" como texto inicial.

Modificar texto con TextFieldBuffer

Un TextFieldBuffer funciona como un contenedor de texto editable, similar en función a un StringBuilder. Contiene el contenido de texto y la información sobre la selección.

A menudo, encontrarás TextFieldBuffer como un alcance del receptor en funciones como TextFieldState.edit, InputTransformation.transformInput o OutputTransformation.transformOutput. En estas funciones, puedes leer o actualizar el TextFieldBuffer según sea necesario. Luego, estos cambios se confirman en TextFieldState o se pasan a la canalización de renderización en el caso de OutputTransformation.

Puedes usar funciones de edición estándar, como append, insert, replace o delete, para modificar el contenido del búfer. Para cambiar el estado de selección, establece directamente su variable selection: TextRange o usa funciones de utilidad, como placeCursorAtEnd o selectAll. La selección en sí se representa con un TextRange, en el que el índice de inicio es inclusivo y el índice de finalización es exclusivo. Un TextRange con valores de inicio y finalización idénticos, como (3, 3), indica una posición del cursor sin caracteres seleccionados.

val phoneNumberState = rememberTextFieldState("1234567890")

TextField(
    state = phoneNumberState,
    keyboardOptions = KeyboardOptions(
        keyboardType = KeyboardType.Phone
    ),
    inputTransformation = InputTransformation.maxLength(10).then {
        if (!asCharSequence().isDigitsOnly()) {
            revertAllChanges()
        }
    },
    outputTransformation = OutputTransformation {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
)

Editar texto en TextFieldState

Existen varios métodos que te permiten editar el estado directamente a través de tu variable de estado:

  • edit: Te permite editar el contenido del estado y te proporciona funciones de TextFieldBuffer para que puedas usar métodos como insert, replace, append y muchos más.

    // Initial textFieldState text passed in is "I love Android"
    // textFieldState.text : I love Android
    // textFieldState.selection: TextRange(14, 14)
    textFieldState.edit { insert(14, "!") }
    // textFieldState.text : I love Android!
    // textFieldState.selection: TextRange(15, 15)
    textFieldState.edit { replace(7, 14, "Compose") }
    // textFieldState.text : I love Compose!
    // textFieldState.selection: TextRange(15, 15)
    textFieldState.edit { append("!!!") }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(18, 18)
    textFieldState.edit { selectAll() }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(0, 18)

  • setTextAndPlaceCursorAtEnd: Borra el texto actual, lo reemplaza por el texto proporcionado y establece el cursor al final.

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

  • clearText: Borra todo el texto.

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

Para conocer otras funciones de TextFieldState, consulta la referencia de TextFieldState.

Modifica la entrada del usuario

En las siguientes secciones, se describe cómo modificar la entrada del usuario. La transformación de entrada te permite filtrar la entrada de TextField mientras el usuario escribe, mientras que la transformación de salida formatea la entrada del usuario antes de que se muestre en pantalla.

Filtra la entrada del usuario con transformaciones de entrada

Una transformación de entrada te permite filtrar la entrada del usuario. Por ejemplo, si tu TextField toma un número de teléfono de EE.UU., solo debes aceptar 10 dígitos. Los resultados de InputTransformation se guardan en TextFieldState.

Existen filtros integrados para casos de uso comunes de InputTransformation. Para limitar la longitud, llama a InputTransformation.maxLength():

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

Transformaciones de entrada personalizadas

InputTransformation es una interfaz de función única. Cuando implementes tu InputTransformation personalizado, deberás anular TextFieldBuffer.transformInput:

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

Para un número de teléfono, agrega una transformación de entrada personalizada que solo permita escribir dígitos en el TextField:

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

Encadena transformaciones de entrada

Para agregar varios filtros a tu entrada de texto, encadena InputTransformation con la función de extensión then. Los filtros se ejecutan de forma secuencial. Como práctica recomendada, aplica primero los filtros más selectivos para evitar transformaciones innecesarias en los datos que, en última instancia, se filtrarían.

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

Después de agregar transformaciones de entrada, la entrada TextField acepta un máximo de 10 dígitos.

Cómo dar formato a la entrada antes de que se muestre

Los OutputTransformation te permiten dar formato a la entrada del usuario antes de que se renderice en la pantalla. A diferencia de InputTransformation, el formato que se aplica a través de OutputTransformation no se guarda en TextFieldState. A partir del ejemplo anterior del número de teléfono, debes agregar paréntesis y guiones en los lugares adecuados:

Un número de teléfono estadounidense con el formato correcto, que incluye paréntesis, guiones y los índices correspondientes.
Figura 3: Un número de teléfono de EE.UU. con el formato adecuado y los índices correspondientes.

Esta es la forma actualizada de controlar los VisualTransformation en los TextField basados en valores, con una diferencia clave: no tienes que calcular sus asignaciones de compensación.

OutputTransformation es una interfaz de método abstracto único. Para implementar un OutputTransformation personalizado, debes anular el método transformOutput:

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

Para dar formato a un número de teléfono, agrega un paréntesis de apertura en el índice 0, un paréntesis de cierre en el índice 4 y un guion en el índice 8 a tu OutputTransformation:

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

A continuación, agrega tu OutputTransformation a TextField:

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

Cómo funcionan las transformaciones en conjunto

En el siguiente diagrama, se muestra el flujo desde la entrada de texto hasta la transformación y la salida:

Visualización de cómo la entrada de texto pasa por transformaciones antes de convertirse en salida de texto.
Figura 4: Diagrama que muestra cómo la entrada de texto pasa por transformaciones antes de convertirse en salida de texto.
  1. La entrada se recibe de la fuente de entrada.
  2. La entrada se filtra a través de un InputTransformation, que se guarda en el TextFieldState.
  3. La entrada se pasa a través de un OutputTransformation para darle formato.
  4. La entrada se presenta en TextField.

Establece opciones del teclado

TextField te permite establecer opciones de configuración del teclado, como el diseño, o bien habilitar la autocorrección si es compatible con el teclado. Es posible que algunas opciones no estén garantizadas si el teclado en pantalla no cumple con las opciones que se proporcionan aquí. Esta es la lista de las opciones de teclado compatibles:

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

La clase KeyboardOptions ahora incluye un nuevo parámetro booleano, showKeyboardOnFocus, que usas específicamente para los componentes TextField que se integran con TextFieldState. Esta opción rige el comportamiento del teclado en pantalla cuando el TextField adquiere el enfoque por medios que no sean la interacción directa del usuario (por ejemplo, de manera programática).

Cuando KeyboardOptions.showKeyboardOnFocus se establece en verdadero, el teclado en pantalla no aparece automáticamente si TextField obtiene el foco de forma indirecta. En esos casos, el usuario debe presionar de forma explícita el TextField para que aparezca el teclado.

Define la lógica de interacción con el teclado

El botón de acción del teclado en pantalla de Android permite respuestas interactivas dentro de tu aplicación. Para obtener más información sobre cómo configurar el botón de acción, consulta la sección Cómo configurar las opciones del teclado.

Un botón de acción del teclado en pantalla (un ícono de marca de verificación) encerrado en un círculo rojo.
Figura 5. Botón de acción del teclado en pantalla

Para definir qué sucede cuando un usuario presiona este botón de acción, usa el parámetro onKeyboardAction. Este parámetro acepta una interfaz funcional opcional llamada KeyboardActionHandler. La interfaz KeyboardActionHandler contiene un solo método, onKeyboardAction(performDefaultAction: () -> Unit). Si proporcionas una implementación para este método onKeyboardAction, puedes introducir una lógica personalizada que se ejecute cuando un usuario presione el botón de acción del teclado.

Varios tipos de acciones de teclado estándar incluyen comportamientos predeterminados integrados. Por ejemplo, si seleccionas ImeAction.Next o ImeAction.Previous como tipo de acción, el enfoque se desplazará de forma predeterminada al campo de entrada posterior o anterior, respectivamente. Del mismo modo, un botón de acción configurado como ImeAction.Done suele descartar el teclado en pantalla. Estas funciones predeterminadas se ejecutan automáticamente y no requieren que proporciones un KeyboardActionHandler.

También puedes implementar un comportamiento personalizado además de estas acciones predeterminadas. Cuando proporcionas tu KeyboardActionHandler, su método onKeyboardAction recibe una función performDefaultAction. Puedes llamar a esta función performDefaultAction() en cualquier punto de tu lógica personalizada para activar también el comportamiento predeterminado estándar asociado con la acción actual del IME.

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

En este fragmento, se ilustra un caso de uso común en una pantalla de registro que incluye un campo de nombre de usuario. En este campo, se selecciona ImeAction.Next para su botón de acción del teclado. Esta opción permite una navegación rápida y fluida al campo de contraseña posterior.

Además de esta navegación estándar, existe el requisito de iniciar un proceso de validación en segundo plano para el nombre de usuario a medida que el usuario ingresa su contraseña. Para garantizar que el comportamiento predeterminado de cambio de enfoque inherente a ImeAction.Next se conserve junto con esta lógica de validación personalizada, se invoca la función performDefaultAction(). Cuando se llama a performDefaultAction(), se activa de forma implícita el sistema de administración de enfoque subyacente para mover el enfoque al siguiente elemento de la IU adecuado, lo que preserva el flujo de navegación esperado.

Crea un campo de contraseña segura

SecureTextField es un elemento componible basado en campos de texto con estado para escribir un campo de contraseña. Te recomendamos que uses SecureTextField para crear campos de texto de contraseña, ya que oculta la entrada de caracteres de forma predeterminada y, además, inhabilita las acciones de cortar y copiar.

SecureTextField tiene un textObfuscationMode, que controla cómo el usuario ve la entrada de caracteres. textObfuscationMode tiene las siguientes opciones:

  • Hidden: Oculta todas las entradas. Es el comportamiento predeterminado en las plataformas de escritorio.

    Es un campo de texto seguro en el que se ocultan los caracteres que se escriben.

  • Visible: Muestra todas las entradas.

    Es un campo de texto seguro en el que se pueden ver los caracteres que se escriben.

  • RevealLastTyped: Oculta toda la entrada, excepto el último carácter. Es el comportamiento predeterminado en dispositivos móviles.

    Un campo de texto seguro en el que solo se revela brevemente el último carácter escrito.

Recursos adicionales