teclado tactil samsung para google descargar como celular cambiar android

tactil - teclado para celular android



Cómo capturar entrada de teclado suave en una vista? (4)

Tengo una vista subclase que aparece en el teclado cuando recibe un ''retoque'' en el evento táctil. Muestra esto al solicitar el foco, recuperar el InputMethodManager y luego llamar a showSoftInput.

Ahora necesito descubrir cómo capturar las letras tocadas del teclado virtual, a medida que se presionan . Actualmente solo recibo una respuesta cuando se presiona el botón Siguiente / Hecho en el teclado virtual.

Aquí está mi clase:

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... // . } }

El teclado muestra, pero mi onKeyListener solo se dispara cuando presiono el botón ''Siguiente'' en el teclado. Necesito el carácter que se toca, para poder mostrarlo en mi método onDraw ().


De acuerdo con la documentation , una View (editor) recibe comandos del Teclado (IME) a ​​través de una documentation y envía comandos al Teclado a través de un InputMethodManager .

Mostraré el código completo a continuación, pero aquí están los pasos.

1. Haz que aparezca el teclado

Como la vista envía un comando al teclado, necesita usar un InputMethodManager . Por el bien del ejemplo, diremos que cuando se toca la vista, se mostrará el teclado (u ocultarlo si ya se muestra).

@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; }

La vista también debe haber establecido setFocusableInTouchMode(true) previamente.

2. Recibir entrada desde el teclado

Para que la vista reciba datos del teclado, debe sobrescribir onCreateInputConnection() . Esto devuelve la InputConnection que usa el teclado para comunicarse con la vista.

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

Los outAttrs especifican qué tipo de teclado está solicitando la vista. Aquí solo solicitamos un teclado de texto normal. Elegir TYPE_CLASS_NUMBER mostraría un teclado numérico (si está disponible). Hay muchas otras opciones. Ver EditorInfo .

Debe devolver una documentation , que generalmente es una subclase personalizada de BaseInputConnection . En esa subclase, proporciona una referencia a su cadena editable, que el teclado actualizará. Como SpannableStringBuilder implementa la interfaz Editable , la usaremos en nuestro ejemplo básico.

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

Todo lo que hicimos aquí fue proporcionar la conexión de entrada con una referencia a la variable de texto en nuestra vista personalizada. El BaseInputConnection se encargará de editar ese mText . Esto podría ser todo lo que necesitas hacer. Sin embargo, puede consultar el código fuente y ver qué métodos dicen "implementación predeterminada", especialmente "la implementación predeterminada no hace nada". Estos son otros métodos que puede desear anular dependiendo de cuán involucrado va a ser su vista de editor. También debe consultar todos los nombres de método en la BaseInputConnection . Varios de ellos tienen notas para "autores del editor". Presta especial atención a esos.

Algunos teclados no envían cierta entrada a través de InputConnection por algún motivo (por ejemplo, delete , ingresar y algunas teclas numéricas ). Para aquellos que agregué un OnKeyListener . Al probar esta configuración en cinco teclados suaves diferentes, todo pareció funcionar. Las respuestas complementarias relacionadas con esto están aquí:

  • Diferenciar el código de clave de texto del código clave de control en Android KeyEvent
  • Necesita tabla de códigos clave para android y presentador
  • Conexión de entrada para teclado de tipo numérico

Código de proyecto completo

Aquí está mi ejemplo completo para referencia.

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>

No hay nada especial en el código MainActivity.java.

Por favor, deje un comentario si esto no funciona para usted. Estoy utilizando esta solución básica para un EditText personalizado en una biblioteca que estoy creando y si hay casos extremos en los que no funciona, quiero saber. Si desea ver ese proyecto, la vista personalizada está here . It''s InputConnection está here .

Relacionado

  • Cómo hacer un teclado de sistema personalizado
  • Cómo hacer un teclado personalizado en la aplicación

En realidad, es posible manejar los eventos clave usted mismo sin derivar su vista de TextView.

Para hacer esto, simplemente modifique su código original de la siguiente manera:

1) Reemplace la siguiente línea en onCreateInputConnection():

outAttrs.inputType = InputType.TYPE_CLASS_TEXT;

Con este:

outAttrs.inputType = InputType.TYPE_NULL;

Según la documentación para InputType.TYPE_NULL: "Esto debe interpretarse en el sentido de que la conexión de entrada de destino no es rica, no puede procesar y mostrar cosas como el texto candidato ni recuperar el texto actual, por lo que el método de entrada deberá ejecutarse en una modo limitado de ''generar eventos clave'' ".

2) Reemplace la siguiente línea en el mismo método:

BaseInputConnection fic = new BaseInputConnection(this, true);

Con este:

BaseInputConnection fic = new BaseInputConnection(this, false);

El segundo argumento falso coloca el BaseInputConnection en el modo "ficticio", que también es necesario para que los eventos clave en bruto se envíen a su vista. En el código BaseInputConnection, puede encontrar varios comentarios como los siguientes: "solo si el modo ficticio, se envía un evento clave para el nuevo texto y se borra el búfer editable actual".

He utilizado este enfoque para hacer que el teclado suave envíe eventos sin procesar a una vista mía que se deriva de LinearLayout (es decir, una vista no derivada de TextView), y puedo confirmar que funciona.

Por supuesto, si no necesita configurar el valor IME_ACTION_DONE imeOptions para mostrar un botón Hecho en el teclado, entonces puede eliminar las onCreateInputConnection() y onCheckIsTextEditor() por completo, y los eventos brutos se enviarán a su vista por defecto, ya que no se habría definido ninguna conexión de entrada capaz de un procesamiento más sofisticado.

Desafortunadamente, no parece haber una manera simple de configurar los atributos de EditorInfo sin reemplazar estos métodos y proporcionar un objeto BaseInputConnection, y una vez que lo haya hecho, tendrá que simplificar el procesamiento realizado por ese objeto como se describe anteriormente si Quiero recibir nuevamente los eventos clave sin procesar.

ADVERTENCIA: Se introdujeron dos errores en ciertas versiones recientes del teclado predeterminado de LatinIME que se envía con Android (teclado de Google) que pueden afectar el procesamiento de eventos del teclado (como se describió anteriormente) cuando ese teclado está en uso. He ideado algunas soluciones en el lado de la aplicación, con código de ejemplo, que parecen evitar estos problemas. Para ver estas soluciones provisionales, consulte la siguiente respuesta:

Android: no se puede capturar retroceso / borrar presionar suavemente. teclado


Resulta que, de hecho, tuve que subclasificar TextView y el uso addTextChangedListener () para agregar mi propia implementación de TextWatcher para escuchar eventos de teclas programables. No pude encontrar una manera de hacer esto con una vista anterior simple.

Otra cosa, para aquellos que probarán esta técnica; TextView no puede editar texto de forma predeterminada, por lo que si desea que su implementación sea editable (en lugar de crear una subclase de EditText, lo que no quería hacer), también debe hacer una InputConnection personalizada, algo como lo siguiente:

/** * 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; } }

A continuación, anula onCheckisTextEditor y onCreateInputConnection con algo como lo siguiente:

@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; }

Después de esto, debe tener una vista que pueda escuchar el teclado virtual y puede hacer lo que quiera con los valores de entrada clave.


Tengo entendido que su onKeyListener solo obtendrá eventos clave de teclado de hardware.

Obtendrá acceso a todos los eventos clave de entrada si anula boolean View.onKeyPreIme(int keyCode, KeyEvent event)

De esta forma puede elegir manejar la acción clave del evento [ DOWN | MULTIPLE | UP ] [ DOWN | MULTIPLE | UP ] [ DOWN | MULTIPLE | UP ] y devuelve true , o permite que el procesamiento de la clave normal lo return super.onKeyPreIme() )