Los editores de texto personalizados son vistas que no son componentes EditText
ni widgets de texto WebView
, pero que, sin embargo, admiten entradas de texto implementando la devolución de llamada onCreateInputConnection()
, a la que se llama cuando una vista está enfocada y el sistema solicita un InputConnection
para la vista.
Una llamada a onCheckIsTextEditor()
desde un editor de texto personalizado debe mostrar true
.
Compatibilidad con la escritura a mano con pluma stylus en editores de texto personalizados
Android 14 (nivel de API 34) y las versiones posteriores admiten la entrada de la pluma stylus en los componentes de entrada de texto estándar de Android de forma predeterminada (consulta Entrada de la pluma stylus en los campos de texto). Sin embargo, los campos (o editores) de entrada de texto personalizados requieren un desarrollo adicional.
Para crear un editor de texto personalizado, haz lo siguiente:
- Habilitar el inicio de escritura a mano
- Cómo declarar la compatibilidad con la escritura a mano
- Admitir gestos de escritura a mano (seleccionar, borrar, insertar, etcétera)
- Cómo proporcionar la ubicación del cursor y otros datos de posición al IME
- Mostrar el ícono de desplazamiento de escritura a mano con la pluma stylus
Habilitar el inicio de escritura a mano
Si una vista consta solo de un editor de texto, el sistema de vistas puede iniciar automáticamente la escritura a mano con la pluma stylus para la vista. De lo contrario, la vista debe implementar su propia lógica de inicio de escritura a mano.
Iniciación automática de escritura a mano
Si una vista muestra un solo editor de texto y ningún otro contenido, puede habilitar la iniciación automática de escritura a mano del sistema de vistas llamando a setAutoHandwritingEnabled(true)
.
Con la escritura a mano automática habilitada, el movimiento de la pluma stylus que comienza en cualquier lugar dentro de los límites de escritura a mano de la vista inicia automáticamente el modo de escritura a mano. El editor de método de entrada (IME) recibe los eventos de movimiento de la pluma stylus y confirma el texto reconocido.
![Campo de entrada con el rectángulo circundante que indica los límites para la detección de eventos de movimiento de la pluma stylus.](https://developer.android.com/static/images/develop/ui/compose/touch-input/stylus-input/shared/edittext_handwriting_bounds.png?authuser=5&hl=es)
EditText
.
Iniciación de escritura a mano personalizada
Si una vista incluye varios editores de texto o contenido, además de uno, debe implementar su propia lógica de inicio de escritura a mano de la siguiente manera:
Inhabilita el inicio automático de escritura a mano del sistema de vista llamando a
setAutoHandwritingEnabled(false)
.Realiza un seguimiento de todos los editores de texto que están visibles en la vista.
Supervisa los eventos de movimiento que recibe la vista en
dispatchTouchEvent()
.Cuando se produce el movimiento de la pluma stylus dentro de los límites de escritura a mano de un editor de texto, enfoca el editor de texto (si aún no está enfocado).
Si el editor no estaba enfocado, reinicia el IME del editor con contenido nuevo llamando a
InputMethodManager#restartInput()
.Para iniciar la sesión de escritura a mano con la pluma stylus, llama a
InputMethodManager#startStylusHandwriting()
.
Si un editor de texto está dentro de una vista desplazable, el movimiento de la pluma stylus dentro de los límites de escritura a mano del editor se debe considerar escritura a mano, no desplazamiento. Usa ViewParent#requestDisallowInterceptTouchEvent()
para evitar que una vista principal desplazable intercepte eventos táctiles de un editor de texto.
Detalles de la API
MotionEvent#getToolType()
: Indica si el objetoMotionEvent
es de una pluma stylus, en cuyo caso el valor que se muestra esTOOL_TYPE_STYLUS
oTOOL_TYPE_ERASER
.InputMethodManager#isStylusHandwritingAvailable()
: Indica si el IME admite la escritura a mano con pluma stylus. Llama a este método antes de cada llamada aInputMethodManager#startStylusHandwriting()
, ya que la disponibilidad de escritura a mano puede haber cambiado.InputMethodManager#startStylusHandwriting()
: Hace que el IME ingrese al modo de escritura a mano. Se envía un evento de movimientoACTION_CANCEL
a la app para cancelar el gesto actual. Ya no se envían a la app los eventos de movimiento de la pluma stylus.Los eventos de movimiento de la pluma stylus del gesto actual que ya se enviaron a la app se reenvían al IME. Se requiere el IME para mostrar una ventana de tinta de la pluma stylus a través de la cual el IME recibe todos los objetos
MotionEvent
siguientes. El IME confirma el texto de escritura a mano reconocido mediante las APIs deInputConnection
.Si el IME no puede ingresar al modo de escritura a mano, esta llamada de método es una no-op.
Cómo declarar la compatibilidad con la escritura a mano
Cuando completes el argumento EditorInfo
de View#onCreateInputConnection(EditorInfo)
, llama a setStylusHandwritingEnabled()
para informar al IME que el editor de texto admite la escritura a mano.
Declara los gestos compatibles con setSupportedHandwritingGestures()
y setSupportedHandwritingGesturePreviews()
.
Compatibilidad con gestos de escritura a mano
Los IME pueden admitir varios gestos de escritura a mano, como encerrar texto en un círculo para seleccionarlo o garabatear texto para borrarlo.
Los editores personalizados implementan InputConnection#performHandwritingGesture()
y InputConnection#previewHandwritingGesture()
para admitir diferentes tipos de HandwritingGesture
, como SelectGesture
, DeleteGesture
y InsertGesture
.
Declara gestos de escritura a mano admitidos cuando completes el argumento EditorInfo
de View#onCreateInputConnection(EditorInfo)
(consulta la sección Cómo declarar la compatibilidad con la escritura a mano).
Detalles de la API
InputConnection#performHandwritingGesture(HandwritingGesture, Executor, IntConsumer)
: Implementa gestos. El argumentoHandwritingGesture
contiene información de ubicación que puedes usar para determinar en qué parte del texto realizar el gesto. Por ejemplo,SelectGesture
proporciona un objetoRectF
que especifica el rango de texto seleccionado, yInsertGesture
proporciona un objetoPointF
que especifica el desplazamiento de texto en el que se insertará texto.Usa los parámetros
Executor
yIntConsumer
para enviar el resultado de la operación. Cuando se proporcionan los argumentos del ejecutor y del consumidor, usa el ejecutor para llamar aIntConsumer#accept()
, por ejemplo:executor.execute { consumer.accept(HANDWRITING_GESTURE_RESULT_SUCCESS) }
HandwritingGesture#getFallbackText()
: Proporciona texto de resguardo que confirma el IME en la posición del cursor si no hay texto aplicable debajo del área de un gesto de escritura a mano.A veces, el IME no puede determinar si un gesto de la pluma stylus está destinado a realizar una operación gestual o escribir texto a mano. Un editor de texto personalizado es responsable de determinar la intención del usuario y realizar la acción adecuada (según el contexto) en la ubicación del gesto.
Por ejemplo, si el IME no puede determinar si el usuario quería dibujar un signo de intercalación hacia abajo ⋁ para realizar un gesto de inserción de espacio o escribir a mano la letra "v", el IME puede enviar una
InsertGesture
con texto alternativo "v".El editor primero debe intentar realizar el gesto de inserción de espacio. Si no se puede realizar el gesto (por ejemplo, no hay texto en la ubicación especificada), el editor debe volver a insertar "v" en la posición del cursor.
InputConnection#previewHandwritingGesture(PreviewableHandwritingGesture, CancellationSignal)
: Muestra una vista previa de un gesto en curso. Por ejemplo, cuando el usuario comienza a dibujar un círculo alrededor de un texto, se puede mostrar una vista previa en vivo de la selección resultante y actualizarla de forma continua a medida que el usuario sigue dibujando. Solo se puede obtener una vista previa de ciertos tipos de gestos (consultaPreviewableHandwritingGesture
).El IME puede usar el parámetro
CancellationSignal
para cancelar la vista previa. Si otros eventos interrumpen la vista previa (por ejemplo, el texto se cambia de manera programática o se producen nuevos comandosInputConnection
), el editor personalizado puede cancelar la vista previa.Los gestos de vista previa son solo para visualización y no deben cambiar el estado del editor. Por ejemplo, una vista previa de
SelectGesture
oculta el rango de selección actual del editor y destaca el rango de vista previa de gestos. Sin embargo, una vez que se cancela la vista previa, el editor debería restablecer su rango de selección anterior.
Cómo proporcionar la ubicación del cursor y otros datos de posición
En el modo de escritura a mano, el IME puede solicitar la ubicación del cursor y otros datos de posición mediante InputConnection#requestCursorUpdates()
.
El editor personalizado responde con una llamada a InputMethodManager#updateCursorAnchorInfo(View,
CursorAnchorInfo)
.
Los datos de CursorAnchorInfo
relevantes para la escritura a mano con la pluma stylus se proporcionan a través de los siguientes métodos CursorAnchorInfo.Builder
:
setInsertionMarkerLocation()
: Establece la ubicación del cursor. El IME usa el valor para animar la tinta de escritura a mano a la ubicación del cursor.setEditorBoundsInfo()
: Establece los límites del editor y de la escritura a mano. El IME usa estos datos para posicionar la barra de herramientas de escritura a mano del IME en la pantalla.addVisibleLineBounds()
: Establece los límites de todas las líneas de texto visibles (o parcialmente visibles) del editor. El IME usa los límites de línea para mejorar la precisión en el reconocimiento de gestos de escritura a mano.setTextAppearanceInfo()
: Establece la apariencia del texto con información derivada del campo de entrada de texto. El IME usa la información para darle estilo a la tinta de escritura a mano.
Mostrar el ícono de desplazamiento de escritura a mano con la pluma stylus
Muestra el ícono de colocar el cursor sobre la escritura a mano con la pluma stylus cuando esta se coloque sobre los límites de escritura a mano de tu editor de texto personalizado y el IME seleccionado admita la escritura a mano con pluma stylus (InputMethodManager#isStylusHandwritingAvailable()
).
Anula View#onResolvePointerIcon()
para obtener un ícono de desplazamiento para escribir a mano con la pluma stylus. En la anulación, llama a PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING)
para acceder al ícono de colocar el cursor sobre la escritura a mano de la pluma stylus del sistema.