Um editor de método de entrada (IME, na sigla em inglês) é um controle que permite que os usuários insiram texto. O Android oferece um framework de método de entrada extensível que permite que os aplicativos ofereçam aos usuários métodos de entrada alternativos, como teclados na tela ou entrada de voz. Depois de instalar os IMEs, o usuário pode selecionar um nas configurações do sistema e usá-lo em todo o sistema. Só é possível ativar um IME por vez.
Para adicionar um IME ao sistema Android, crie um app Android que contenha uma classe que
estenda
InputMethodService.
Além disso, geralmente é criada uma atividade de "configurações" que transmite opções para o serviço de IME. Você
também pode definir uma interface de configurações que é mostrada como parte das configurações do sistema.
Nesta página, abordamos os seguintes tópicos:
- O ciclo de vida do IME
- Como declarar componentes do IME no manifesto do aplicativo
- API IME
- Como criar uma interface de IME
- Como enviar texto de um IME para um aplicativo
- Como trabalhar com subtipos de IME
- Outras considerações sobre o IME
Se você não trabalhou com IMEs, leia primeiro o artigo introdutório Métodos de entrada na tela.
O ciclo de vida do IME
O diagrama a seguir descreve o ciclo de vida de um IME:
As seções a seguir descrevem como implementar a interface e o código associados a um IME que segue esse ciclo de vida.
Declarar os componentes do IME no manifesto
No sistema Android, um IME é um aplicativo para Android que contém um serviço de IME especial. O
arquivo de manifesto do aplicativo precisa declarar o serviço, solicitar as permissões necessárias, fornecer um
filtro de intent que corresponda à ação action.view.InputMethod e fornecer metadados
que definam as características do IME. Além disso, para fornecer uma interface de configurações que permita ao
usuário modificar o comportamento do IME, você pode definir uma atividade de "configurações" que pode ser iniciada nas
Configurações do sistema.
O snippet a seguir declara um serviço de IME. Ele solicita a permissão
BIND_INPUT_METHOD
para permitir que o serviço conecte o IME ao sistema, configura um filtro de intent que corresponde à ação
android.view.InputMethod e define metadados para o IME:
<!-- Declares the input method service. --> <service android:name="FastInputIME" android:label="@string/fast_input_label" android:permission="android.permission.BIND_INPUT_METHOD"> <intent-filter> <action android:name="android.view.InputMethod" /> </intent-filter> <meta-data android:name="android.view.im" android:resource="@xml/method" /> </service>
O próximo snippet declara a atividade de configurações do IME. Ele tem um filtro de intent para
ACTION_MAIN que
indica que essa atividade é o ponto de entrada principal do aplicativo de IME:
<!-- Optional: an activity for controlling the IME settings. --> <activity android:name="FastInputIMESettings" android:label="@string/fast_input_settings"> <intent-filter> <action android:name="android.intent.action.MAIN"/> </intent-filter> </activity>
Também é possível fornecer acesso às configurações do IME diretamente pela interface.
A API do método de entrada
As classes específicas para IMEs são encontradas nos pacotes
android.inputmethodservice
e
android.view.inputmethod. A classe KeyEvent é
importante para processar caracteres do teclado.
A parte central de um IME é um componente de serviço, uma classe que estende
InputMethodService. Além de implementar o ciclo de vida normal do serviço, essa
classe tem callbacks para fornecer a interface do IME, processar a entrada do usuário e enviar texto para o
campo em foco. Por padrão, a classe InputMethodService fornece a maior parte da
implementação para gerenciar o estado e a visibilidade do IME e se comunicar com o campo de entrada
atual.
As seguintes classes também são importantes:
BaseInputConnection-
Define o canal de comunicação de um
InputMethodde volta para o aplicativo que está recebendo a entrada. Você pode usá-lo para ler o texto ao redor do cursor, confirmar o texto para a caixa de texto e enviar eventos de chave brutos para o aplicativo. Os aplicativos precisam estender essa classe em vez de implementar a interface baseInputConnection. KeyboardView-
Uma extensão de
Viewque renderiza um teclado e responde a eventos de entrada do usuário. O layout do teclado é especificado por uma instância deKeyboard, que pode ser definida em um arquivo XML.
Projetar a IU do método de entrada
Há dois elementos visuais principais para um IME: a visualização de entrada e a visualização de candidatos. Você só precisa implementar os elementos relevantes para o método de entrada que está projetando.
Visualização de entrada
A visualização de entrada é a interface em que o usuário insere texto na forma de cliques em teclas, escrita à mão ou
gestos. Quando o IME é exibido pela primeira vez, o sistema chama o callback
onCreateInputView(). Na implementação desse método, crie o layout que você quer mostrar na janela do IME
e retorne o layout para o sistema. O snippet abaixo mostra um exemplo de implementação
do método onCreateInputView():
Kotlin
override fun onCreateInputView(): View { return layoutInflater.inflate(R.layout.input, null).apply { if (this is MyKeyboardView) { setOnKeyboardActionListener(this@MyInputMethod) keyboard = latinKeyboard } } }
Java
@Override public View onCreateInputView() { MyKeyboardView inputView = (MyKeyboardView) getLayoutInflater().inflate(R.layout.input, null); inputView.setOnKeyboardActionListener(this); inputView.setKeyboard(latinKeyboard); return inputView; }
Neste exemplo, MyKeyboardView é uma instância de uma implementação personalizada de
KeyboardView que renderiza um Keyboard.
Visualização candidata
A visualização de candidatos é a interface em que o IME mostra possíveis correções ou sugestões de palavras
para o usuário selecionar. No ciclo de vida do IME, o sistema chama
onCreateCandidatesView()
quando está pronto para mostrar a visualização de candidatos. Na implementação desse método, retorne um
layout que mostre sugestões de palavras ou retorne nulo se não quiser mostrar nada. Uma resposta nula é o comportamento padrão. Portanto, não é necessário implementar isso se você não fornecer sugestões.
Considerações sobre o design da interface
Nesta seção, descrevemos algumas considerações de design de interface para IMEs.
Processar vários tamanhos de tela
A interface do IME precisa ser dimensionável para diferentes tamanhos de tela e lidar com as orientações paisagem e retrato. No modo de IME que não é de tela cheia, deixe espaço suficiente para que o aplicativo mostre o campo de texto e qualquer contexto associado, de modo que não mais do que metade da tela seja ocupada pelo IME. No modo IME de tela cheia, isso não é um problema.
Processar diferentes tipos de entrada
Os campos de texto do Android permitem definir um tipo de entrada específico, como texto de formato livre, números, URLs, endereços de e-mail e strings de pesquisa. Ao implementar um novo IME, detecte o tipo de entrada de cada campo e forneça a interface adequada para ele. No entanto, não é necessário configurar o IME para verificar se o usuário insere um texto válido para o tipo de entrada. Isso é responsabilidade do aplicativo que possui o campo de texto.
Por exemplo, esta é a interface que o IME latino fornece para a entrada de texto da plataforma Android:
E aqui está a interface que o IME latino fornece para a entrada numérica da plataforma Android:
Quando um campo de entrada recebe foco e o IME é iniciado, o sistema chama
onStartInputView(),
transmitindo um
objeto EditorInfo
que contém detalhes sobre o tipo de entrada e outros atributos do campo de texto. Nesse objeto,
o
campo
inputType
contém o tipo de entrada do campo de texto.
O campo inputType é um int que contém padrões de bits para várias
configurações de tipo de entrada. Para testar o tipo de entrada do campo de texto, mascare-o com a constante
TYPE_MASK_CLASS,
desta forma:
Kotlin
inputType and InputType.TYPE_MASK_CLASS
Java
inputType & InputType.TYPE_MASK_CLASS
O padrão de bits do tipo de entrada pode ter um dos vários valores, incluindo:
TYPE_CLASS_NUMBER- Um campo de texto para inserir números. Como ilustrado na figura 3, o IME Latin exibe um teclado numérico para campos desse tipo.
TYPE_CLASS_DATETIME- Um campo de texto para inserir uma data e hora.
TYPE_CLASS_PHONE- Um campo de texto para inserir números de telefone.
TYPE_CLASS_TEXT- Um campo de texto para inserir qualquer caractere aceito.
Essas constantes são descritas em mais detalhes na documentação de referência de
InputType.
O campo inputType pode conter outros bits que indicam uma variante do tipo de campo de texto, como:
TYPE_TEXT_VARIATION_PASSWORD- Uma variante de
TYPE_CLASS_TEXTpara inserir senhas. O método de entrada exibe dingbats em vez do texto real. TYPE_TEXT_VARIATION_URI- Uma variante de
TYPE_CLASS_TEXTpara inserir URLs da Web e outros identificadores uniformes de recursos (URIs). TYPE_TEXT_FLAG_AUTO_COMPLETE- Uma variante de
TYPE_CLASS_TEXTpara inserir texto que o aplicativo preenche automaticamente usando um dicionário, uma pesquisa ou outro recurso.
Mascare inputType com a constante adequada ao testar essas variantes. As
constantes de máscara disponíveis estão listadas na documentação de referência de InputType.
Enviar texto para o aplicativo
Conforme o usuário insere texto com o IME, é possível enviar texto para o aplicativo enviando eventos de tecla individuais
ou editando o texto ao redor do cursor no campo de texto do aplicativo. Em ambos os casos,
use uma instância de InputConnection para enviar o texto. Para acessar essa instância, chame
InputMethodService.getCurrentInputConnection().
Editar o texto ao redor do cursor
Ao lidar com a edição de um texto, alguns métodos úteis em
BaseInputConnection são os seguintes:
-
getTextBeforeCursor() - Retorna um
CharSequenceque contém o número de caracteres solicitados antes da posição atual do cursor. -
getTextAfterCursor() - Retorna uma
CharSequenceque contém o número de caracteres solicitados após a posição atual do cursor. -
deleteSurroundingText() - Exclui o número especificado de caracteres antes e depois da posição atual do cursor.
-
commitText() - Confirma um
CharSequenceno campo de texto e define uma nova posição do cursor.
Por exemplo, o snippet abaixo mostra como substituir os quatro caracteres à esquerda do cursor pelo texto "Hello!":
Kotlin
currentInputConnection.also { ic: InputConnection -> ic.deleteSurroundingText(4, 0) ic.commitText("Hello", 1) ic.commitText("!", 1) }
Java
InputConnection ic = getCurrentInputConnection(); ic.deleteSurroundingText(4, 0); ic.commitText("Hello", 1); ic.commitText("!", 1);
Suporte para escrever um texto antes de confirmar
Se o IME prevê texto ou requer várias etapas para compor um glifo ou uma palavra, é possível mostrar o
progresso no campo de texto até que o usuário confirme a palavra e, em seguida, substituir a composição
parcial pelo texto concluído. Você pode dar um tratamento especial ao texto adicionando um
span a ele ao transmiti-lo para
setComposingText().
O snippet abaixo demonstra como mostrar o progresso em um campo de texto:
Kotlin
currentInputConnection.also { ic: InputConnection -> ic.setComposingText("Composi", 1) ic.setComposingText("Composin", 1) ic.commitText("Composing ", 1) }
Java
InputConnection ic = getCurrentInputConnection(); ic.setComposingText("Composi", 1); ic.setComposingText("Composin", 1); ic.commitText("Composing ", 1);
Interceptar eventos de chave de hardware
Mesmo que a janela do método de entrada não tenha foco explícito, ela recebe eventos de tecla de hardware primeiro e pode consumi-los ou encaminhá-los ao aplicativo. Por exemplo, talvez você queira consumir as teclas direcionais para navegar na IU para seleção de candidatos durante a composição. Também é recomendável interceptar a tecla "Voltar" para dispensar as caixas de diálogo originadas da janela do método de entrada.
Para interceptar chaves de hardware, substitua
onKeyDown()
e
onKeyUp().
Chame o método super() para as chaves que você não quer processar.
Criar um subtipo de IME
Os subtipos permitem que o IME exponha vários modos de entrada e idiomas compatíveis. Um subtipo pode representar o seguinte:
- Uma localidade, como en_US ou fr_FR
- um modo de entrada, como voz, teclado ou escrita à mão;
- Outros estilos, formulários ou propriedades de entrada específicos do IME, como layouts de teclado de 10 teclas ou QWERTY.
O modo pode ser qualquer texto, como "teclado" ou "voz". Um subtipo também pode expor uma combinação desses elementos.
As informações de subtipo são usadas para uma caixa de diálogo de troca de IME disponível na barra de notificações e para as configurações de IME. As informações também permitem que o framework mostre um subtipo específico de um IME diretamente. Ao criar um IME, use o recurso de subtipo, porque ele ajuda o usuário a identificar e alternar entre diferentes idiomas e modos de IME.
Defina subtipos em um dos arquivos de recursos XML do método de entrada usando o
elemento <subtype>. O snippet de código abaixo define um IME com dois subtipos: um
subtipo de teclado para a localidade de inglês dos EUA e outro para a localidade de francês
da França:
<input-method xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="com.example.softkeyboard.Settings" android:icon="@drawable/ime_icon"> <subtype android:name="@string/display_name_english_keyboard_ime" android:icon="@drawable/subtype_icon_english_keyboard_ime" android:languageTag="en-US" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="somePrivateOption=true" /> <subtype android:name="@string/display_name_french_keyboard_ime" android:icon="@drawable/subtype_icon_french_keyboard_ime" android:languageTag="fr-FR" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="someVariable=30,someInternalOption=false" /> <subtype android:name="@string/display_name_german_keyboard_ime" ... /> </input-method>
Para garantir que os subtipos sejam rotulados corretamente na interface, use `%s` para receber um rótulo de subtipo que seja igual ao rótulo de localidade do subtipo. Isso é demonstrado nos próximos dois snippets de código. O primeiro snippet mostra parte do arquivo XML do método de entrada:
<subtype android:label="@string/label_subtype_generic" android:imeSubtypeLocale="en_US" android:icon="@drawable/icon_en_us" android:imeSubtypeMode="keyboard" />
O snippet seguinte faz parte do arquivo strings.xml do IME. O recurso de string
label_subtype_generic, que é usado pela definição da IU do método de entrada para definir o
rótulo do subtipo, é definido da seguinte maneira:
<string name="label_subtype_generic">%s</string>Essa configuração faz com que o nome de exibição do subtipo corresponda à configuração de localidade. Por exemplo, em qualquer localidade em inglês, o nome de exibição é "English (United States)".
Escolher os subtipos de IME na barra de notificações
O sistema Android gerencia todos os subtipos expostos por todos os IMEs. Os subtipos de IME são tratados como modos do IME ao qual pertencem. O usuário pode navegar da barra de notificações ou do app Configurações para um menu de subtipos de IME disponíveis, como mostrado na figura a seguir:
Escolher os subtipos de IME nas configurações do sistema
O usuário também pode controlar como os subtipos são usados no painel de configurações Idioma e entrada nas configurações do sistema:
Alternar entre os subtipos de IME
Para permitir que os usuários alternem facilmente entre os subtipos de IME, forneça uma tecla de interruptor, como o ícone de idioma em forma de globo no teclado. Isso melhora a usabilidade do teclado e é conveniente para o usuário. Para ativar essa alternância, siga estas etapas:
- Declare
supportsSwitchingToNextInputMethod = "true"nos arquivos de recursos XML do método de entrada. A declaração precisa ser semelhante ao snippet de código abaixo:<input-method xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="com.example.softkeyboard.Settings" android:icon="@drawable/ime_icon" android:supportsSwitchingToNextInputMethod="true">
- Chame o método
shouldOfferSwitchingToNextInputMethod(). - Se o método retornar "verdadeiro", exiba um botão de alternância.
- Quando o usuário tocar na tecla de interruptor, chame
switchToNextInputMethod(), transmitindo "false". Um valor falso informa ao sistema para tratar todos os subtipos igualmente, independentemente do IME a que pertencem. Especificar "true" exige que o sistema percorra os subtipos no IME atual.
Considerações gerais sobre IME
Confira outros aspectos a serem considerados ao implementar o IME:
- Ofereça uma forma para que os usuários ativem opções diretamente da IU do IME.
- Ofereça uma maneira de os usuários mudarem para um IME diferente diretamente na interface do método de entrada, já que vários IMEs podem estar instalados no dispositivo.
- Chame a IU do IME rapidamente. Pré-carregue ou carregue sob demanda todos os recursos grandes para que os usuários vejam o IME assim que tocarem em um campo de texto. Armazene em cache recursos e visualizações para invocações subsequentes do método de entrada.
- Libere grandes alocações de memória imediatamente após a janela do método de entrada ser ocultada para que os aplicativos tenham memória suficiente para serem executados. Use uma mensagem atrasada para liberar recursos se o IME estiver oculto por alguns segundos.
- Verifique se os usuários podem inserir o máximo de caracteres possível para o idioma ou local associado ao IME. Os usuários podem usar pontuação em senhas ou nomes de usuário. Portanto, o IME precisa fornecer muitos caracteres diferentes para que os usuários possam inserir uma senha e acessar o dispositivo.