Come catturare l'input soft della tastiera in una vista?

Ho una vista sottoclass che apre la tastiera quando riceve un "touch" in onTouchEvent. Mostra questo richiesto fuoco, recuperando InputMethodManager e quindi chiamando showSoftInput.

Ora devo scoprire come catturare le lettere digitate della tastiera soft, in quanto vengono premute . Al momento riceve una risposta solo quando il button Next / Done è premuto sulla tastiera soft.

  • Google Analytics v4 - dati non visualizzati sul cruscotto
  • HTC Sensation Reale Risoluzione
  • Come posizionare widget UI in cima a più Z ha ordinato le visualizzazioni di superficie in Android
  • errore quando applica plugin: 'com.google.gms.google-services'
  • Android: sovrapposizione sull'apparecchiatura Android Preview
  • adb non viene riconosciuto come command interno o esterno sulle windows
  • Ecco la mia class:

    public class BigGrid extends View { private static final String TAG = "BigGrid"; public BigGrid(Context context) { super(context); setFocusableInTouchMode(true); // allows the keyboard to pop up on // touch down setOnKeyListener(new OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { Log.d(TAG, "onKeyListener"); if (event.getAction() == KeyEvent.ACTION_DOWN) { // Perform action on key press Log.d(TAG, "ACTION_DOWN"); return true; } return false; } }); } @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); Log.d(TAG, "onTOUCH"); if (event.getAction() == MotionEvent.ACTION_UP) { // show the keyboard so we can enter text InputMethodManager imm = (InputMethodManager) getContext() .getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(this, InputMethodManager.SHOW_FORCED); } return true; } @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { Log.d(TAG, "onCreateInputConnection"); BaseInputConnection fic = new BaseInputConnection(this, true); outAttrs.actionLabel = null; outAttrs.inputType = InputType.TYPE_CLASS_TEXT; outAttrs.imeOptions = EditorInfo.IME_ACTION_NEXT; return fic; } @Override public boolean onCheckIsTextEditor() { Log.d(TAG, "onCheckIsTextEditor"); return true; } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(R.color.grid_bg); // . // . // alot more drawing code... // . } } 

    La tastiera mostra, ma il mio onKeyListener si accende solo quando premo il button 'Avanti' sulla tastiera. Ho bisogno di quale carattere viene toccato, in modo che possa visualizzarlo nel mio metodo onDraw ().

    4 Solutions collect form web for “Come catturare l'input soft della tastiera in una vista?”

    In realtà è ansible gestire gli events chiave senza wherer derivare la tua visuale da TextView.

    Per fare questo, modificate semplicemente il codice originale come segue:

    1) Sostituire la seguente row in onCreateInputConnection():

     outAttrs.inputType = InputType.TYPE_CLASS_TEXT; 

    con questo:

     outAttrs.inputType = InputType.TYPE_NULL; 

    Per la documentazione di InputType.TYPE_NULL: "Questo deve essere interpretato nel senso che la connessione di input di destinazione non è ricca, non può elaborare e mostrare cose come il text candidato né recuperare il text corrente, quindi il metodo di input dovrà essere eseguito in un limitata "generazione di events chiave". "

    2) Sostituire la seguente row nello stesso metodo:

     BaseInputConnection fic = new BaseInputConnection(this, true); 

    con questo:

     BaseInputConnection fic = new BaseInputConnection(this, false); 

    Il falso secondo argomento mette la BaseInputConnection in modalità "dummy", che è anche necessaria affinché gli events chiave di origine siano inviati alla visualizzazione. Nel codice BaseInputConnection, è ansible trovare diversi commenti, ad esempio: "solo se si utilizza la modalità dummy, viene inviato un evento chiave per il nuovo text e il buffer corrente modificabile".

    Ho usato questo approccio per avere la tastiera soft submit gli events crudi a una vista della mia derivata da LinearLayout (cioè una vista non derivata da TextView) e può confermare che funziona.

    Naturalmente, se non è necessario impostare il valore IME_ACTION_DONE imeOptions per mostrare un button Fine sulla tastiera, è sufficiente rimuovere l' onCreateInputConnection() e onCheckIsTextEditor() ignora completamente e gli events crudi verranno quindi inviati alla visualizzazione per impostazione predefinita, poiché non era stata definita alcuna connessione di ingresso in grado di elaborare più sofisticati.

    Ma purtroppo non sembra essere un modo semplice per configurare gli attributi EditorInfo senza prevalere questi methods e fornire un object BaseInputConnection e una volta che hai fatto che dovrai annullare l'elaborazione eseguita da quel object come descritto in precedenza se vogliono ancora una volta ricevere gli events chiave di base.

    AVVERTENZA: in alcune versioni recenti della tastiera predefinita LatinIME fornita con Android (Google Keyboard) che sono in grado di influenzare l'elaborazione di events della tastiera (come descritto in precedenza) sono stati introdotti due bug in alcune ultime versioni della tastiera predefinita LatinIME. Ho elaborato alcune soluzioni sul lato dell'app, con codice di esempio, che sembrano aggirare questi problemi. Per visualizzare queste soluzioni, vedere la seguente risposta:

    Android – non riesce a catturare il backspace / cancellare premere in soft. tastiera

    Risulta che ho effettivamente bisogno di sottostrarsi a TextView e utilizzare l'addTextChangedListener () per aggiungere la mia propria implementazione di TextWatcher per ascoltare events chiave soft. Non riuscivo a trovare un modo per farlo con una vecchia vista pura.

    Un'altra cosa, per coloro che provano questa tecnica; TextView non è in grado di modificare il text per impostazione predefinita, quindi se si desidera rendere la tua implementazione modificabile (anziché la sottoclass di EditText, che non volevo fare), è necessario anche creare un InputConnection personalizzato, come nel seguente esempio:

      /** * MyInputConnection * BaseInputConnection configured to be editable */ class MyInputConnection extends BaseInputConnection { private SpannableStringBuilder _editable; TextView _textView; public MyInputConnection(View targetView, boolean fullEditor) { super(targetView, fullEditor); _textView = (TextView) targetView; } public Editable getEditable() { if (_editable == null) { _editable = (SpannableStringBuilder) Editable.Factory.getInstance() .newEditable("Placeholder"); } return _editable; } public boolean commitText(CharSequence text, int newCursorPosition) { _editable.append(text); _textView.setText(text); return true; } } 

    Poi si sovrascrivono onCheckisTextEditor e onCreateInputConnection con qualcosa del tipo seguente:

      @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { outAttrs.actionLabel = null; outAttrs.label = "Test text"; outAttrs.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS; outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE; return new MyInputConnection(this, true); } @Override public boolean onCheckIsTextEditor() { return true; } 

    Dopo di che, è necessario disporre di una vista che può ascoltare la tastiera morbida e si può fare tutto ciò che si desidera con i valori di input chiave.

    Secondo la documentazione , un View (editor) riceve comandi dalla tastiera (IME) tramite un InputConnection e invia comandi alla tastiera tramite un InputMethodManager .

    immettere qui la descrizione dell'immagine

    Mostrerò l'integer codice qui sotto, ma qui sono i passi.

    1. Fare apparire la tastiera

    Poiché la vista invia un command alla tastiera, è necessario utilizzare un InputMethodManager . Per favore dell'esempio, diremo che quando viene visualizzata la vista, mostrerà la tastiera (o nasconderla se è già visualizzata).

     @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_IMPLICIT_ONLY); } return true; } 

    Anche la vista deve avere impostato setFocusableInTouchMode(true) precedenza.

    2. Ricevere l'input dalla tastiera

    Affinché la vista possa ricevere l'input dalla tastiera, deve superare onCreateInputConnection() . Questo restituisce l' InputConnection utilizzato dalla tastiera per comunicare con la vista.

     @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { outAttrs.inputType = InputType.TYPE_CLASS_TEXT; return new MyInputConnection(this, true); } 

    Gli outAttrs specificano quale tipo di tastiera la vista sta richiedendo. Qui stiamo solo chiedendo una normale tastiera di text. La scelta di TYPE_CLASS_NUMBER potrebbe visualizzare un block numbersco (se disponibile). Ci sono molte altre opzioni. Consultare EditorInfo .

    È necessario restituire un InputConnection , che di solito è una sottoclass personalizzata di BaseInputConnection . In questa sottoclass si fornisce un riferimento alla string modificabile, che la tastiera apporterà gli aggiornamenti. Poiché SpannableStringBuilder implementa l'interface Editable , lo useremo nell'esempio di base.

     public class MyInputConnection extends BaseInputConnection { private SpannableStringBuilder mEditable; MyInputConnection(View targetView, boolean fullEditor) { super(targetView, fullEditor); MyCustomView customView = (MyCustomView) targetView; mEditable = customView.mText; } @Override public Editable getEditable() { return mEditable; } } 

    Tutto quello che abbiamo fatto qui è stato quello di fornire la connessione di input con un riferimento alla variabile di text nella nostra visualizzazione personalizzata. La BaseInputConnection si occuperà della modifica di mText . Questo potrebbe benissimo essere tutto quello che devi fare. Tuttavia, puoi controllare il codice sorgente e vedere quali methods dicono "implementazione predefinita", in particolare "l'implementazione predefinita non fa nulla". Questi sono altri methods che si desidera sovrascrivere a seconda di come la visualizzazione dell'editor sarà coinvolta. Dovresti anche guardare tutti i nomi di metodo nella documentazione . Alcuni di loro hanno nota di "autori di editor". Prestare particolare attenzione a quelle.

    Alcune tastiere non trasmettono alcun ingresso attraverso l' InputConnection per qualche motivo (ad esempio l' eliminazione , l'inserimento e alcuni tasti del tastierino numbersco ). Per quelli ho aggiunto un OnKeyListener . Testando questa configuration su cinque diverse tastiere morbide, tutto sembrava funzionare. Risposte complementari relative a questo sono qui:

    • Differenziare il codice chiave del text dal codice di controllo in Android KeyEvent
    • Hai bisogno di una tabella dei codici chiave per Android e presentatore
    • Connessione in ingresso per tastiera tipo numbersco

    Codice completo del progetto

    Ecco il mio esempio completo per riferimento.

    immettere qui la descrizione dell'immagine

    MyCustomView.java

     public class MyCustomView extends View { SpannableStringBuilder mText; public MyCustomView(Context context) { this(context, null, 0); } public MyCustomView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { setFocusableInTouchMode(true); mText = new SpannableStringBuilder(); // handle key presses not handled by the InputConnection setOnKeyListener(new OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (event.getUnicodeChar() == 0) { // control character if (keyCode == KeyEvent.KEYCODE_DEL) { mText.delete(mText.length() - 1, mText.length()); Log.i("TAG", "text: " + mText + " (keycode)"); return true; } // TODO handle any other control keys here } else { // text character mText.append((char)event.getUnicodeChar()); Log.i("TAG", "text: " + mText + " (keycode)"); return true; } } return false; } }); } // toggle whether the keyboard is showing when the view is clicked @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_IMPLICIT_ONLY); } return true; } @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { outAttrs.inputType = InputType.TYPE_CLASS_TEXT; // outAttrs.inputType = InputType.TYPE_CLASS_NUMBER; // alternate (show number pad rather than text) return new MyInputConnection(this, true); } } 

    MyInputConnection.java

     public class MyInputConnection extends BaseInputConnection { private SpannableStringBuilder mEditable; MyInputConnection(View targetView, boolean fullEditor) { super(targetView, fullEditor); MyCustomView customView = (MyCustomView) targetView; mEditable = customView.mText; } @Override public Editable getEditable() { return mEditable; } // just adding this to show that text is being committed. @Override public boolean commitText(CharSequence text, int newCursorPosition) { boolean returnValue = super.commitText(text, newCursorPosition); Log.i("TAG", "text: " + mEditable); return returnValue; } } 

    activity_main.xml

     <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.editorview.MainActivity"> <com.example.editorview.MyCustomView android:id="@+id/myCustomView" android:background="@android:color/holo_blue_bright" android:layout_margin="50dp" android:layout_width="300dp" android:layout_height="150dp" android:layout_centerHorizontal="true" /> </RelativeLayout> 

    Non c'è niente di speciale nel codice MainActivity.java.

    Lasciate un commento se questo non funziona per te. Sto usando questa soluzione di base per un EditText personalizzato in una libreria che sto facendo e se ci sono dei casi in cui non funziona, voglio sapere. Se vuoi visualizzare questo progetto, la visualizzazione personalizzata è qui . È InputConnection è qui .

    Relazionato

    • Come creare una tastiera personalizzata del sistema
    • Come creare una tastiera personalizzata in-app

    La mia comprensione è che il tuo onKeyListener solo gli events chiave della tastiera hardware.

    Potrai accedere a tutti gli events della chiave di input se boolean View.onKeyPreIme(int keyCode, KeyEvent event)

    In questo modo è ansible scegliere di gestire l'azione degli events chiave [ DOWN | MULTIPLE | UP ] [ DOWN | MULTIPLE | UP ] [ DOWN | MULTIPLE | UP ] e restituirà true oppure consentire l'elaborazione di chiave normale ( return super.onKeyPreIme() )

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.