Editores de texto personalizados

Editores de texto personalizados são visualizações que não são componentes EditText ou widgets de texto WebView, mas oferecem suporte à entrada de texto implementando o callback onCreateInputConnection(), que é chamado quando uma visualização é focada e o sistema solicita um InputConnection para ela.

Uma chamada para onCheckIsTextEditor() de um editor de texto personalizado precisa retornar true.

Suporte à escrita à mão com a stylus em editores de texto personalizados

O Android 14 (nível 34 da API) e versões mais recentes oferecem suporte à entrada da stylus em componentes de entrada de texto padrão do Android por padrão. Consulte Entrada da stylus em campos de texto. No entanto, os campos (ou editores) de entrada de texto personalizados exigem desenvolvimento adicional.

Para criar um editor de texto personalizado, faça o seguinte:

  1. Ativar iniciação de escrita à mão
  2. Declarar compatibilidade com escrita à mão
  3. Suporte a gestos de escrita à mão (selecionar, excluir, inserir etc.)
  4. Forneça a localização do cursor e outros dados de posição para o IME
  5. Mostrar o ícone de escrita à mão ao passar o cursor da stylus

Ativar iniciação de escrita à mão

Se uma visualização consistir apenas em um único editor de texto, o sistema de visualização poderá iniciar automaticamente a escrita à mão da stylus para a visualização. Caso contrário, a visualização precisará implementar a própria lógica de início de escrita à mão.

Iniciação automática de escrita à mão

Se uma visualização mostrar um único editor de texto e nenhum outro conteúdo, ela poderá ativar a iniciação automática de escrita à mão do sistema de visualização chamando setAutoHandwritingEnabled(true).

Com a escrita automática à mão ativada, o movimento da stylus a partir de qualquer lugar dentro dos limites de escrita à mão da visualização inicia automaticamente o modo de escrita à mão. O Editor de método de entrada (IME) recebe os eventos de movimento da stylus e confirma o texto reconhecido.

Campo de entrada com retângulo ao redor indicando os limites para a detecção de eventos de movimento da stylus.
Figura 1. Escrita à mão dentro dos limites de um campo EditText.

Iniciação de escrita à mão personalizada

Se uma visualização tiver vários editores de texto ou conteúdo, além de um único editor de texto, ela precisará implementar a própria lógica de início de escrita à mão da seguinte maneira:

  1. Desative a iniciação automática de escrita à mão do sistema de visualização chamando setAutoHandwritingEnabled(false).

  2. Acompanhe todos os editores de texto visíveis na visualização.

  3. Monitore os eventos de movimento recebidos pela visualização em dispatchTouchEvent().

    • Quando o movimento da stylus ocorrer dentro dos limites de escrita à mão de um editor de texto, foque no editor de texto (se ele ainda não estiver em foco).

    • Se o editor ainda não estiver em foco, reinicie o IME (editor de método de entrada, na sigla em inglês) dele com novos conteúdos chamando InputMethodManager#restartInput().

    • Inicie a sessão de escrita à mão da stylus chamando InputMethodManager#startStylusHandwriting().

Se um editor de texto estiver dentro de uma visualização rolável, o movimento da stylus dentro dos limites de escrita à mão do editor será considerado escrita à mão, não rolagem. Use ViewParent#requestDisallowInterceptTouchEvent() para evitar que uma visualização ancestral rolável intercepte eventos de toque de um editor de texto.

Detalhes da API

  • MotionEvent#getToolType(): indica se o MotionEvent é de uma stylus. Nesse caso, o valor de retorno é TOOL_TYPE_STYLUS ou TOOL_TYPE_ERASER.

  • InputMethodManager#isStylusHandwritingAvailable(): indica se o IME oferece suporte à escrita à mão com a stylus. Chame esse método antes de cada chamada para InputMethodManager#startStylusHandwriting(), já que a disponibilidade da escrita à mão pode ter mudado.

  • InputMethodManager#startStylusHandwriting(): faz com que o IME entre no modo de escrita à mão. Um evento de movimento ACTION_CANCEL é enviado ao app para cancelar o gesto atual. Os eventos de movimento da stylus não são mais enviados para o app.

    Os eventos de movimento da stylus do gesto atual que já foram enviados ao app são encaminhados para o IME. O IME é necessário para mostrar uma janela de tinta da stylus em que o IME recebe todos os objetos MotionEvent seguintes. O IME confirma texto de escrita à mão reconhecido usando as APIs InputConnection.

    Se o IME não puder entrar no modo de escrita à mão, essa chamada de método será um ambiente autônomo.

Declarar compatibilidade com escrita à mão

Ao preencher o argumento EditorInfo de View#onCreateInputConnection(EditorInfo), chame setStylusHandwritingEnabled() para informar ao IME que o editor de texto oferece suporte à escrita à mão. Declare os gestos compatíveis usando setSupportedHandwritingGestures() e setSupportedHandwritingGesturePreviews().

Suporte a gestos de escrita à mão

Os IMEs podem oferecer suporte a vários gestos de escrita à mão, como circular texto para selecioná-lo ou rabiscar sobre o texto para excluí-lo.

Figura 2. Circule para selecionar o texto.
Figura 3. Rabisque para excluir texto.

Os editores personalizados implementam InputConnection#performHandwritingGesture() e InputConnection#previewHandwritingGesture() para oferecer suporte a diferentes tipos de HandwritingGesture, como SelectGesture, DeleteGesture e InsertGesture.

Declare os gestos de escrita à mão compatíveis ao preencher o argumento EditorInfo de View#onCreateInputConnection(EditorInfo). Consulte a seção Declarar suporte à escrita à mão.

Detalhes da API

  • InputConnection#performHandwritingGesture(HandwritingGesture, Executor, IntConsumer) : implementa gestos. O argumento HandwritingGesture contém informações de localização que podem ser usadas para determinar em que parte do texto o gesto será realizado. Por exemplo, SelectGesture fornece um objeto RectF que especifica o intervalo de texto selecionado, e InsertGesture fornece um objeto PointF que especifica o deslocamento do texto em que o texto será inserido.

    Use os parâmetros Executor e IntConsumer para enviar o resultado da operação. Quando os argumentos do executor e do consumidor forem fornecidos, use o executor para chamar IntConsumer#accept(), por exemplo:

    
    executor.execute { consumer.accept(HANDWRITING_GESTURE_RESULT_SUCCESS) }
    
    
  • HandwritingGesture#getFallbackText(): fornece o texto substituto que o IME confirma na posição do cursor se nenhum texto aplicável estiver abaixo da área de um gesto de escrita à mão.

    Às vezes, o IME não consegue determinar se um gesto da stylus se destina a executar uma operação de gesto ou escrever texto à mão. Um editor de texto personalizado é responsável por determinar a intenção do usuário e realizar a ação adequada (dependendo do contexto) no local do gesto.

    Por exemplo, se o IME não puder determinar se o usuário pretendia desenhar um circunflexo para baixo ⋁ para executar um gesto de inserção de espaço ou escrever à mão a letra "v", o IME poderá enviar um InsertGesture com o texto substituto "v".

    Primeiro, o editor precisa tentar executar o gesto de inserção de espaço. Se o gesto não puder ser executado (por exemplo, não houver texto no local especificado), o editor voltará a inserir "v" na posição do cursor.

  • InputConnection#previewHandwritingGesture(PreviewableHandwritingGesture, CancellationSignal) : visualiza um gesto em andamento. Por exemplo, conforme o usuário começa a desenhar um círculo ao redor de um texto, uma visualização em tempo real da seleção resultante pode ser mostrada e atualizada continuamente à medida que o usuário continua desenhando. Apenas determinados tipos de gestos podem ser visualizados. Consulte PreviewableHandwritingGesture.

    O parâmetro CancellationSignal pode ser usado pelo IME para cancelar a visualização. Se outros eventos interromperem a visualização (por exemplo, se o texto for alterado de maneira programática ou a ocorrência de novos comandos InputConnection), o editor personalizado poderá cancelar a visualização.

    Os gestos de visualização são apenas para exibição e não podem mudar o estado do editor. Por exemplo, uma visualização de SelectGesture oculta o intervalo de seleção atual do editor e destaca o intervalo de visualização de gesto. No entanto, depois que a visualização for cancelada, o editor vai restaurar o intervalo de seleção anterior.

Forneça a localização do cursor e outros dados de posição

No modo de escrita à mão, o IME pode solicitar a localização do cursor e outros dados de posição usando InputConnection#requestCursorUpdates(). O editor personalizado responde com uma chamada para InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo). Os dados em CursorAnchorInfo relevantes para a escrita à mão da stylus são fornecidos pelos seguintes métodos CursorAnchorInfo.Builder:

  • setInsertionMarkerLocation(): define o local do cursor. O IME usa o valor para animar a tinta de escrita à mão no local do cursor.
  • setEditorBoundsInfo(): define os limites do editor e da escrita à mão. O IME usa esses dados para posicionar a barra de ferramentas de escrita à mão dele na tela.
  • addVisibleLineBounds(): define os limites de todas as linhas de texto visíveis (ou parcialmente visíveis) do editor. O IME usa os limites de linha para melhorar a precisão no reconhecimento de gestos de escrita à mão.
  • setTextAppearanceInfo(): define a aparência do texto com informações derivadas do campo de entrada de texto. O IME usa as informações para definir o estilo da tinta de escrita à mão.

Mostrar o ícone de escrita à mão ao passar o cursor da stylus

Mostre o ícone de escrita à mão da stylus quando ela passar o cursor sobre os limites de escrita à mão do editor de texto personalizado e o IME selecionado oferecer suporte à escrita à mão com a stylus (InputMethodManager#isStylusHandwritingAvailable()).

Modifique View#onResolvePointerIcon() para receber um ícone de passar o cursor para a escrita à mão da stylus. Na substituição, chame PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING) para acessar o ícone de passar o cursor por escrita à mão da stylus do sistema.

Outros recursos