Crea un metodo di immissione

Un editor del metodo di immissione (IME) è un controllo utente che consente agli utenti di inserire testo. Android fornisce un framework di metodi di immissione estensibile che consente alle applicazioni di fornire agli utenti metodi di immissione alternativi, come tastiere sullo schermo o input vocale. Dopo aver installato gli IME, l'utente può selezionarne uno dalle impostazioni di sistema e utilizzarlo in tutto il sistema. È possibile attivare un solo IME alla volta.

Per aggiungere un IME al sistema Android, crea un'app per Android contenente una classe che estende InputMethodService. Inoltre, di solito crei un'attività "Impostazioni" che passa le opzioni al servizio IME. Puoi anche definire una UI delle impostazioni che viene visualizzata come parte delle impostazioni di sistema.

Questa pagina tratta i seguenti argomenti:

Se non hai mai lavorato con gli IME, leggi prima l'articolo introduttivo Metodi di immissione sullo schermo.

Il ciclo di vita dell'IME

Il seguente diagramma descrive il ciclo di vita di un IME:

Un'immagine che mostra il ciclo di vita di un IME.
Figura 1. Il ciclo di vita di un IME.

Le sezioni seguenti descrivono come implementare la UI e il codice associati a un IME che segue questo ciclo di vita.

Dichiara i componenti IME nel manifest

Nel sistema Android, un IME è un'app per Android che contiene un servizio IME speciale. Il file manifest dell'applicazione deve dichiarare il servizio, richiedere le autorizzazioni necessarie, fornire un filtro per intent corrispondente all'azione action.view.InputMethod e fornire metadati che definiscono le caratteristiche dell'IME. Inoltre, per fornire un'interfaccia delle impostazioni che consenta all'utente di modificare il comportamento dell'IME, puoi definire un'attività "Impostazioni" che può essere avviata dalle Impostazioni di sistema.

Il seguente snippet dichiara un servizio IME. Richiede l'autorizzazione BIND_INPUT_METHOD per consentire al servizio di connettere l'IME al sistema, configura un filtro per intent che corrisponde all'azione android.view.InputMethod e definisce i metadati per l'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>

Lo snippet successivo dichiara l'attività delle impostazioni per l'IME. Contiene un filtro per intent per ACTION_MAIN che indica che questa attività è l'entry point principale per l'applicazione 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>

Puoi anche fornire l'accesso alle impostazioni dell'IME direttamente dalla sua UI.

L'API del metodo di immissione

Le classi specifiche per gli IME si trovano nei pacchetti android.inputmethodservice e android.view.inputmethod. La classe KeyEvent è importante per la gestione dei caratteri della tastiera.

La parte centrale di un IME è un componente di servizio, una classe che estende InputMethodService. Oltre a implementare il normale ciclo di vita del servizio, questa classe dispone di callback per fornire l'UI dell'IME, gestire l'input dell'utente e inviare il testo al campo attivo. Per impostazione predefinita, la classe InputMethodService fornisce la maggior parte dell'implementazione per la gestione dello stato e della visibilità dell'IME e per la comunicazione con il campo di immissione corrente.

Anche le seguenti classi sono importanti:

BaseInputConnection
Definisce il canale di comunicazione da un InputMethod all'applicazione che riceve il suo input. Lo utilizzi per leggere il testo intorno al cursore, inserire il testo nella casella di testo e inviare eventi chiave non elaborati all'applicazione. Le applicazioni devono estendere questa classe anziché implementare l'interfaccia di base InputConnection.
KeyboardView
Un'estensione di View che esegue il rendering di una tastiera e risponde agli eventi di input dell'utente. Il layout di tastiera è specificato da un'istanza di Keyboard, che puoi definire in un file XML.

Progetta l'interfaccia utente del metodo di immissione

Esistono due elementi visivi principali per un IME: la visualizzazione di input e la visualizzazione dei candidati. Devi implementare solo gli elementi pertinenti al metodo di immissione che stai progettando.

Visualizzazione di input

La visualizzazione di input è l'interfaccia utente in cui l'utente inserisce il testo sotto forma di clic sui tasti, scrittura a mano libera o gesti. Quando l'IME viene visualizzato per la prima volta, il sistema chiama il callback onCreateInputView(). Nella tua implementazione di questo metodo, crea il layout che vuoi visualizzare nella finestra dell'IME e restituiscilo al sistema. Il seguente snippet mostra un esempio di implementazione del metodo 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;
}

In questo esempio, MyKeyboardView è un'istanza di un'implementazione personalizzata di KeyboardView che esegue il rendering di un Keyboard.

Visualizzazione dei candidati

La visualizzazione dei candidati è l'interfaccia utente in cui l'IME mostra potenziali correzioni o suggerimenti di parole che l'utente può selezionare. Nel ciclo di vita dell'IME, il sistema chiama onCreateCandidatesView() quando è pronto per visualizzare la visualizzazione dei candidati. Nella tua implementazione di questo metodo, restituisci un layout che mostri i suggerimenti per la scelta delle parole o restituisci null se non vuoi mostrare nulla. Una risposta null è il comportamento predefinito, quindi non è necessario implementarla se non fornisci suggerimenti.

Considerazioni sulla progettazione della UI

Questa sezione descrive alcune considerazioni sulla progettazione della UI per gli IME.

Gestisci più dimensioni dello schermo

La UI dell'IME deve essere in grado di adattarsi a schermi di dimensioni diverse e di gestire sia l'orientamento orizzontale sia quello verticale. In modalità IME non a schermo intero, lascia spazio sufficiente affinché l'applicazione possa mostrare il campo di testo e l'eventuale contesto associato, in modo che non più della metà dello schermo sia occupata dall'IME. In modalità IME a schermo intero, questo non è un problema.

Gestisci diversi tipi di input

I campi di testo Android ti consentono di impostare un tipo di input specifico, ad esempio testo in formato libero, numeri, URL, indirizzi email e stringhe di ricerca. Quando implementi un nuovo IME, rileva il tipo di input di ogni campo e fornisci l'interfaccia appropriata. Tuttavia, non è necessario configurare l'IME per verificare se l'utente inserisce un testo valido per il tipo di input. Questa è responsabilità dell'applicazione proprietaria del campo di testo.

Ad esempio, ecco l'interfaccia fornita dall'IME latino per l'inserimento di testo sulla piattaforma Android:

Un'immagine che mostra un input di testo su un IME latino
Figura 2. Inserimento di testo con IME latino.

Ecco l'interfaccia fornita dall'IME latino per l'input numerico della piattaforma Android:

Un'immagine che mostra un input numerico su un IME latino
Figura 3. Input numerico IME latino.

Quando un campo di immissione riceve lo stato attivo e l'IME si avvia, il sistema chiama onStartInputView(), passando un oggetto EditorInfo che contiene i dettagli sul tipo di input e altri attributi del campo di testo. In questo oggetto, il campo inputType contiene il tipo di input del campo di testo.

Il campo inputType è un int che contiene pattern di bit per varie impostazioni del tipo di input. Per testarlo per il tipo di input del campo di testo, mascheratelo con la costante TYPE_MASK_CLASS, in questo modo:

Kotlin

inputType and InputType.TYPE_MASK_CLASS

Java

inputType & InputType.TYPE_MASK_CLASS

Il pattern di bit del tipo di input può avere uno dei seguenti valori:

TYPE_CLASS_NUMBER
Un campo di testo per l'inserimento di numeri. Come illustrato nella Figura 3, l'IME latino mostra un tastierino numerico per i campi di questo tipo.
TYPE_CLASS_DATETIME
Un campo di testo per l'inserimento di una data e un'ora.
TYPE_CLASS_PHONE
Un campo di testo per l'inserimento di numeri di telefono.
TYPE_CLASS_TEXT
Un campo di testo per l'inserimento di qualsiasi carattere supportato.

Queste costanti sono descritte in maggiore dettaglio nella documentazione di riferimento per InputType.

Il campo inputType può contenere altri bit che indicano una variante del tipo di campo di testo, ad esempio:

TYPE_TEXT_VARIATION_PASSWORD
Una variante di TYPE_CLASS_TEXT per l'inserimento delle password. Il metodo di immissione mostra dingbat anziché il testo effettivo.
TYPE_TEXT_VARIATION_URI
Una variante di TYPE_CLASS_TEXT per l'inserimento di URL web e altri URI (Uniform Resource Identifier).
TYPE_TEXT_FLAG_AUTO_COMPLETE
Una variante di TYPE_CLASS_TEXT per l'inserimento di testo che l'applicazione completa automaticamente da un dizionario, una ricerca o un'altra funzionalità.

Maschera inputType con la costante appropriata quando esegui il test per queste varianti. Le costanti di maschera disponibili sono elencate nella documentazione di riferimento di InputType.

Inviare testo all'applicazione

Mentre l'utente inserisce il testo con l'IME, puoi inviare il testo all'applicazione inviando singoli eventi chiave o modificando il testo intorno al cursore nel campo di testo dell'applicazione. In entrambi i casi, utilizza un'istanza di InputConnection per fornire il testo. Per ottenere questa istanza, chiama InputMethodService.getCurrentInputConnection().

Modifica il testo intorno al cursore

Quando gestisci la modifica di un testo esistente, alcuni metodi utili in BaseInputConnection sono i seguenti:

getTextBeforeCursor()
Restituisce un CharSequence contenente il numero di caratteri richiesti prima della posizione attuale del cursore.
getTextAfterCursor()
Restituisce un CharSequence contenente il numero di caratteri richiesti dopo la posizione corrente del cursore.
deleteSurroundingText()
Elimina il numero specificato di caratteri prima e dopo la posizione corrente del cursore.
commitText()
Esegue il commit di un CharSequence nel campo di testo e imposta una nuova posizione del cursore.

Ad esempio, il seguente snippet mostra come sostituire i quattro caratteri a sinistra del cursore con il testo "Ciao!":

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);

Supporto della composizione del testo prima del commit

Se l'IME prevede il testo o richiede più passaggi per comporre un glifo o una parola, puoi mostrare l'avanzamento nel campo di testo finché l'utente non conferma la parola, quindi puoi sostituire la composizione parziale con il testo completato. Puoi applicare un trattamento speciale al testo aggiungendo uno span quando lo passi a setComposingText().

Il seguente snippet mostra come visualizzare l'avanzamento in un campo di testo:

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);

Intercetta gli eventi dei tasti hardware

Anche se la finestra del metodo di immissione non ha lo stato attivo esplicito, riceve prima gli eventi dei tasti hardware e può utilizzarli o inoltrarli all'applicazione. Ad esempio, potresti voler utilizzare i tasti direzionali per navigare all'interno della UI per la selezione dei candidati durante la composizione. Potresti anche voler intercettare il tasto Indietro per chiudere eventuali finestre di dialogo provenienti dalla finestra del metodo di immissione.

Per intercettare i tasti hardware, esegui l'override di onKeyDown() e onKeyUp().

Chiama il metodo super() per i tasti che non vuoi gestire autonomamente.

Crea un sottotipo IME

I sottotipi consentono all'IME di esporre più modalità di immissione e lingue supportate dall'IME. Un sottotipo può rappresentare quanto segue:

  • Un'impostazione internazionale, ad esempio en_US o fr_FR
  • Una modalità di input, ad esempio vocale, tastiera o scrittura a mano libera
  • Altri stili, moduli o proprietà di input specifici dell'IME, come i layout di tastiera a 10 tasti o QWERTY

La modalità può essere qualsiasi testo, ad esempio "tastiera" o "voce". Un sottotipo può anche esporre una combinazione di questi elementi.

Le informazioni sul sottotipo vengono utilizzate per una finestra di dialogo del selettore IME disponibile nella barra delle notifiche e per le impostazioni IME. Le informazioni consentono inoltre al framework di visualizzare direttamente un sottotipo specifico di un IME. Quando crei un IME, utilizza la funzionalità dei sottotipi, perché aiuta l'utente a identificare e passare da una lingua e una modalità IME all'altra.

Definisci i sottotipi in uno dei file di risorse XML del metodo di immissione utilizzando l'elemento <subtype>. Il seguente snippet di codice definisce un IME con due sottotipi: un sottotipo di tastiera per le impostazioni internazionali dell'inglese americano e un altro sottotipo di tastiera per le impostazioni internazionali della lingua francese per la Francia:

<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>

Per assicurarti che i sottotipi siano etichettati correttamente nell'UI, utilizza "%s" per ottenere un'etichetta del sottotipo uguale a quella delle impostazioni internazionali del sottotipo. Questo è dimostrato nei due snippet di codice successivi. Il primo snippet mostra parte del file XML del metodo di immissione:

<subtype
    android:label="@string/label_subtype_generic"
    android:imeSubtypeLocale="en_US"
    android:icon="@drawable/icon_en_us"
    android:imeSubtypeMode="keyboard" />

Lo snippet successivo fa parte del file strings.xml dell'IME. La risorsa stringa label_subtype_generic, utilizzata dalla definizione della UI del metodo di immissione per impostare l'etichetta del sottotipo, è definita come segue:

<string name="label_subtype_generic">%s</string>

Questa impostazione fa sì che il nome visualizzato del sottotipo corrisponda all'impostazione delle impostazioni internazionali. Ad esempio, in qualsiasi impostazione internazionale inglese, il nome visualizzato è "Inglese (Stati Uniti)".

Scegli i sottotipi di IME dalla barra delle notifiche

Il sistema Android gestisce tutti i sottotipi esposti da tutti gli IME. I sottotipi di IME vengono trattati come modalità dell'IME a cui appartengono. L'utente può spostarsi dalla barra di notifica o dall'app Impostazioni a un menu dei sottotipi di IME disponibili, come mostrato nella figura seguente:

Un'immagine che mostra il menu di sistema Lingue e immissione
Figura 4. Il menu di sistema Lingue e immissione.

Scegli i sottotipi di IME dalle Impostazioni di sistema

L'utente può anche controllare l'utilizzo dei sottotipi nel riquadro delle impostazioni Lingua e immissione nelle impostazioni di sistema:

Un'immagine che mostra il menu di selezione delle lingue
Figura 5. Il menu di sistema Lingue

Passa da un sottotipo di IME all'altro

Puoi consentire agli utenti di passare facilmente da un sottotipo di IME all'altro fornendo un tasto di commutazione, ad esempio l'icona della lingua a forma di globo sulla tastiera. In questo modo, l'usabilità della tastiera migliora e l'utente ha un'esperienza più comoda. Per attivare questa opzione, segui questi passaggi:

  1. Dichiara supportsSwitchingToNextInputMethod = "true" nei file di risorse XML del metodo di immissione. La dichiarazione deve essere simile al seguente snippet di codice:
    <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">
  2. Chiama il metodo shouldOfferSwitchingToNextInputMethod().
  3. Se il metodo restituisce true, mostra un tasto del sensore.
  4. Quando l'utente tocca il tasto del sensore, chiama switchToNextInputMethod(), passando false. Un valore false indica al sistema di trattare tutti i sottotipi allo stesso modo, indipendentemente dall'IME a cui appartengono. Se specifichi true, il sistema deve scorrere i sottotipi nell'IME corrente.

Considerazioni generali sugli IME

Ecco altri aspetti da considerare durante l'implementazione dell'IME:

  • Offri agli utenti un modo per impostare le opzioni direttamente dalla UI dell'IME.
  • Offri agli utenti un modo per passare a un IME diverso direttamente dalla UI del metodo di immissione, perché sul dispositivo potrebbero essere installati più IME.
  • Visualizzare rapidamente l'interfaccia utente dell'IME. Precarica o carica on demand le risorse di grandi dimensioni in modo che gli utenti vedano l'IME non appena toccano un campo di testo. Memorizza nella cache le risorse e le visualizzazioni per le chiamate successive del metodo di immissione.
  • Rilascia le allocazioni di memoria di grandi dimensioni immediatamente dopo che la finestra del metodo di immissione è stata nascosta, in modo che le applicazioni abbiano memoria sufficiente per l'esecuzione. Utilizza un messaggio ritardato per rilasciare le risorse se l'IME è nascosto per alcuni secondi.
  • Assicurati che gli utenti possano inserire il maggior numero possibile di caratteri per la lingua o le impostazioni internazionali associate all'IME. Gli utenti potrebbero utilizzare la punteggiatura nelle password o nei nomi utente, quindi l'IME deve fornire molti caratteri diversi per consentire agli utenti di inserire una password e accedere al dispositivo.