Crea un teclado personalizado en Android
Spanish (Español) translation by Ana Paulina Figueroa (you can also view the original English article)



La mayoría de los dispositivos Android no cuentan con un teclado físico. En vez de eso dependen de un teclado virtual o de pantalla para aceptar la entrada del usuario. Si te interesa la personalización de Android, saber cómo construir un teclado de pantalla a medida puede elevar tu pasatiempo a un nivel completamente nuevo.
Usando el SDK de Android puedes crear rápidamente un teclado de pantalla, sorprendentemente con pocas líneas de código, ya que el SDK se encarga de muchas de las tareas de bajo nivel, tales como reconocer las pulsaciones de las teclas, dibujar el teclado y establecer las conexiones entre el teclado y los campos de entrada.
En este tutorial aprenderás cómo crear un teclado de pantalla totalmente funcional que podrá servir como teclado predeterminado para tu dispositivo Android.
1. Requisitos previos
Necesitarás el paquete Eclipse ADT instalado. Puedes descargarlo desde el sitio web Android Developer.
2. Crea un nuevo proyecto
Ejecuta Eclipse y crea una nueva aplicación Android. Asigna el nombre SimpleKeyboard a la aplicación. Asegúrate de elegir un nombre de paquete único. Establece el SDK mínimo requerido en Android 2.2 y configura el SDK de destino con el valor Android 4.4.



Esta aplicación no tendrá actividades, así que quita la selección en Crear Actividad y haz clic en Finalizar.



3. Edita el Manifiesto
Un teclado de pantalla es considerado como un Input Method Editor (IME), o editor de método de entrada, por el sistema operativo Android. Un IME es declarado como un Service en AndroidManifest.xml que usa el permiso BIND_INPUT_METHOD y responde a la acción android.view.InputMethod.
Agrega las siguientes líneas a la etiqueta application del manifiesto:
1 |
<service android:name=".SimpleIME" |
2 |
android:label="@string/simple_ime" |
3 |
android:permission="android.permission.BIND_INPUT_METHOD" |
4 |
>
|
5 |
<meta-data android:name="android.view.im" android:resource="@xml/method"/> |
6 |
<intent-filter>
|
7 |
<action android:name="android.view.InputMethod" /> |
8 |
</intent-filter>
|
9 |
</service>
|
4. Crea method.xml
La etiqueta service en el archivo de manifiesto contiene una etiqueta meta-data que hace referencia a un archivo XML llamado method.xml. Sin este archivo, el sistema operativo Android no reconocerá nuestro Service como un servicio IME válido. El archivo contiene detalles acerca del método de entrada y sus subtipos. En el caso de nuestro teclado, definimos un subtipo simple para la configuración regional en_US. Crea el directorio res/xml si no existe y agrégale el archivo method.xml. El contenido del archivo debe ser el siguiente:
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<input-method xmlns:android="https://schemas.android.com/apk/res/android"> |
3 |
<subtype
|
4 |
android:label="@string/subtype_en_US" |
5 |
android:imeSubtypeLocale="en_US" |
6 |
android:imeSubtypeMode="keyboard" /> |
7 |
</input-method>
|
5. Edita strings.xml
Las cadenas que usa esta aplicación están definidas en el archivo res/values/strings.xml. Vamos a necesitar tres cadenas:
- El nombre de la aplicación
- La etiqueta del IME
- La etiqueta de subtipo del IME
Actualiza tu archivo strings.xml para que contenga lo siguiente:
1 |
<resources>
|
2 |
<string name="app_name">SimpleKeyboard</string> |
3 |
<string name="simple_ime">Simple IME</string> |
4 |
<string name="subtype_en_US">English (US)</string> |
5 |
</resources>
|
6. Define el diseño del teclado
El diseño de nuestro teclado contiene solamente un KeyboardView. El atributo layout_alignParentBottom está configurado en true para que el teclado aparezca en la parte inferior de la pantalla.
Crea un archivo con el nombre res/layout/keyboard.xml y reemplaza su contenido con lo siguiente:
1 |
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
<android.inputmethodservice.KeyboardView
|
3 |
xmlns:android="http://schemas.android.com/apk/res/android" |
4 |
android:id="@+id/keyboard" |
5 |
android:layout_width="match_parent" |
6 |
android:layout_height="wrap_content" |
7 |
android:layout_alignParentBottom="true" |
8 |
android:keyPreviewLayout ="@layout/preview" |
9 |
/>
|
El keyPreviewLayout es el diseño de la pantalla emergente de corta duración que aparece cada vez que se presiona una tecla del teclado. Este contiene un único TextView. Crea un archivo llamado res/layout/preview.xml y agrégale lo siguiente:
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<TextView xmlns:android="http://schemas.android.com/apk/res/android" |
3 |
android:layout_width="match_parent" |
4 |
android:layout_height="match_parent" |
5 |
android:gravity="center" |
6 |
android:background="#ffff00" |
7 |
android:textStyle="bold" |
8 |
android:textSize="30sp" |
9 |
>
|
10 |
</TextView>
|
6. Define las teclas del teclado
Los detalles de las teclas del teclado y sus posiciones se especifican en un archivo XML. Cada tecla tiene los siguientes atributos:
-
keyLabel: Este atributo contiene el texto que se muestra en la tecla. -
codes: Este atributo contiene los valores unicode de los caracteres representados por la tecla.
Por ejemplo, para definir una tecla para la letra A, el atributo codes debe tener el valor 97 y el atributo keyLabel debe establecerse con el valor A.
Si hay más de un código asociado a una tecla, entonces el carácter que la tecla representa dependerá del número de pulsaciones que reciba. Por ejemplo, si una tecla tiene los códigos 63, 33 y 58:
- Una pulsación simple en el teclado dará como resultado el carácter ?
- Dos pulsaciones en sucesión rápida darán como resultado el carácter !
- Tres pulsaciones en sucesión rápida resultarán en el carácter :
Una tecla también puede tener algunos atributos opcionales:
-
keyEdgeFlags: Este atributo puede tener el valorleftoright. Usualmente se añade a las teclas que se encuentran más a la izquierda y más a la derecha en una fila. -
keyWidth: Este atributo define el ancho de una tecla. Usualmente se establece como un valor porcentual. -
isRepeatable: Si este atributo tiene el valortrue, al hacer una pulsación de larga duración sobre la tecla se repetirá la acción de dicha tecla varias veces. Usualmente se establece entruepara la tecla de borrar y para la barra espaciadora.
Las teclas de un teclado están agrupadas en filas. Es una buena práctica limitar el número de teclas en una fila a un máximo de diez, asignando a cada tecla un ancho igual al 10% del teclado. La altura de las teclas está configurada en 60dp en este tutorial. Esta cifra puede ajustarse, pero los valores menores a 48dp no son recomendables. Nuestro teclado tendrá cinco filas de teclas.
Ahora podemos continuar y diseñar el teclado. Crea un archivo nuevo llamado res/xml/qwerty.xml y reemplaza su contenido con lo siguiente:
1 |
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android" |
2 |
android:keyWidth="10%p" |
3 |
android:horizontalGap="0px" |
4 |
android:verticalGap="0px" |
5 |
android:keyHeight="60dp" |
6 |
>
|
7 |
<Row>
|
8 |
<Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/> |
9 |
<Key android:codes="50" android:keyLabel="2"/> |
10 |
<Key android:codes="51" android:keyLabel="3"/> |
11 |
<Key android:codes="52" android:keyLabel="4"/> |
12 |
<Key android:codes="53" android:keyLabel="5"/> |
13 |
<Key android:codes="54" android:keyLabel="6"/> |
14 |
<Key android:codes="55" android:keyLabel="7"/> |
15 |
<Key android:codes="56" android:keyLabel="8"/> |
16 |
<Key android:codes="57" android:keyLabel="9"/> |
17 |
<Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/> |
18 |
</Row>
|
19 |
<Row>
|
20 |
<Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/> |
21 |
<Key android:codes="119" android:keyLabel="w"/> |
22 |
<Key android:codes="101" android:keyLabel="e"/> |
23 |
<Key android:codes="114" android:keyLabel="r"/> |
24 |
<Key android:codes="116" android:keyLabel="t"/> |
25 |
<Key android:codes="121" android:keyLabel="y"/> |
26 |
<Key android:codes="117" android:keyLabel="u"/> |
27 |
<Key android:codes="105" android:keyLabel="i"/> |
28 |
<Key android:codes="111" android:keyLabel="o"/> |
29 |
<Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/> |
30 |
</Row>
|
31 |
<Row>
|
32 |
<Key android:codes="97" android:keyLabel="a" android:keyEdgeFlags="left"/> |
33 |
<Key android:codes="115" android:keyLabel="s"/> |
34 |
<Key android:codes="100" android:keyLabel="d"/> |
35 |
<Key android:codes="102" android:keyLabel="f"/> |
36 |
<Key android:codes="103" android:keyLabel="g"/> |
37 |
<Key android:codes="104" android:keyLabel="h"/> |
38 |
<Key android:codes="106" android:keyLabel="j"/> |
39 |
<Key android:codes="107" android:keyLabel="k"/> |
40 |
<Key android:codes="108" android:keyLabel="l"/> |
41 |
<Key android:codes="35,64" android:keyLabel="\# \@" android:keyEdgeFlags="right"/> |
42 |
</Row>
|
43 |
<Row>
|
44 |
<Key android:codes="-1" android:keyLabel="CAPS" android:keyEdgeFlags="left"/> |
45 |
<Key android:codes="122" android:keyLabel="z"/> |
46 |
<Key android:codes="120" android:keyLabel="x"/> |
47 |
<Key android:codes="99" android:keyLabel="c"/> |
48 |
<Key android:codes="118" android:keyLabel="v"/> |
49 |
<Key android:codes="98" android:keyLabel="b"/> |
50 |
<Key android:codes="110" android:keyLabel="n"/> |
51 |
<Key android:codes="109" android:keyLabel="m"/> |
52 |
<Key android:codes="46" android:keyLabel="."/> |
53 |
<Key android:codes="63,33,58" android:keyLabel="\? ! :" android:keyEdgeFlags="right"/> |
54 |
</Row>
|
55 |
<Row android:rowEdgeFlags="bottom"> |
56 |
<Key android:codes="44" android:keyLabel="," android:keyWidth="10%p" android:keyEdgeFlags="left"/> |
57 |
<Key android:codes="47" android:keyLabel="/" android:keyWidth="10%p" /> |
58 |
<Key android:codes="32" android:keyLabel="SPACE" android:keyWidth="40%p" android:isRepeatable="true"/> |
59 |
<Key android:codes="-5" android:keyLabel="DEL" android:keyWidth="20%p" android:isRepeatable="true"/> |
60 |
<Key android:codes="-4" android:keyLabel="DONE" android:keyWidth="20%p" android:keyEdgeFlags="right"/> |
61 |
</Row>
|
62 |
</Keyboard>
|
Quizá hayas notado que algunas teclas tienen valores negativos para el atributo codes. Los valores negativos son iguales a las constantes predefinidas en la clase Keyboard. Por ejemplo, el valor -5 es igual al valor de Keyboard.KEYCODE_DELETE.
7. Crea una clase Service
Crea una nueva clase de Java y llámale SimpleIME.java. Esta debe extender a la clase InputMethodService e implementar la interfaz OnKeyboardActionListener. La interfaz OnKeyboardActionListener contiene los métodos que se invocan cuando las teclas del teclado de pantalla son pulsadas o presionadas.
La clase SimpleIME debe tener tres variables miembro:
- Una
KeyboardViewhaciendo referencia a la vista definida en el diseño - Una instancia de
Keyboardque se asigna aKeyboardView - Una
booleanque nos indique si el bloqueo de mayúsculas está habilitado
Después de declarar estas variables y de agregar los métodos de la interfaz OnKeyboardActionListener, la clase SimpleIME deberá verse así:
1 |
public class SimpleIME extends InputMethodService |
2 |
implements OnKeyboardActionListener{ |
3 |
|
4 |
private KeyboardView kv; |
5 |
private Keyboard keyboard; |
6 |
|
7 |
private boolean caps = false; |
8 |
|
9 |
@Override
|
10 |
public void onKey(int primaryCode, int[] keyCodes) { |
11 |
|
12 |
}
|
13 |
|
14 |
@Override
|
15 |
public void onPress(int primaryCode) { |
16 |
}
|
17 |
|
18 |
@Override
|
19 |
public void onRelease(int primaryCode) { |
20 |
}
|
21 |
|
22 |
@Override
|
23 |
public void onText(CharSequence text) { |
24 |
}
|
25 |
|
26 |
@Override
|
27 |
public void swipeDown() { |
28 |
}
|
29 |
|
30 |
@Override
|
31 |
public void swipeLeft() { |
32 |
}
|
33 |
|
34 |
@Override
|
35 |
public void swipeRight() { |
36 |
}
|
37 |
|
38 |
@Override
|
39 |
public void swipeUp() { |
40 |
}
|
41 |
}
|
Cuando el teclado es creado se invoca el método onCreateInputView. Todas las variables miembro de Service pueden inicializarse aquí. Actualiza la implementación del método onCreateInputView como se muestra a continuación:
1 |
@Override
|
2 |
public View onCreateInputView() { |
3 |
kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null); |
4 |
keyboard = new Keyboard(this, R.xml.qwerty); |
5 |
kv.setKeyboard(keyboard); |
6 |
kv.setOnKeyboardActionListener(this); |
7 |
return kv; |
8 |
}
|
Enseguida creamos un método que reproduce un sonido cuando se presiona una tecla. Usamos la clase AudioManager para reproducir los sonidos. El SDK de Android incluye algunos efectos de sonido predeterminados para las pulsaciones de las teclas y estos son los que se usan en el método playClick.
1 |
private void playClick(int keyCode){ |
2 |
AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE); |
3 |
switch(keyCode){ |
4 |
case 32: |
5 |
am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR); |
6 |
break; |
7 |
case Keyboard.KEYCODE_DONE: |
8 |
case 10: |
9 |
am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN); |
10 |
break; |
11 |
case Keyboard.KEYCODE_DELETE: |
12 |
am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE); |
13 |
break; |
14 |
default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD); |
15 |
}
|
16 |
}
|
Por último, actualiza el método onKey para que nuestra aplicación de teclado pueda comunicarse con los campos de entrada (usualmente las vistas EditText) de otras aplicaciones.
El método getCurrentInputConnection se usa para obtener una conexión al campo de entrada de otra aplicación. Una vez que tengamos la conexión podemos usar los siguientes métodos:
-
commitTextpara añadir uno o más caracteres al campo de entrada -
deleteSurroundingTextpara borrar uno o más caracteres del campo de entrada -
sendKeyEventpara enviar eventos, comoKEYCODE_ENTER, a la aplicación externa
Cada vez que un usuario presiona una tecla en el teclado de pantalla, el método onKey es invocado usando el valor unicode de la tecla como uno de sus parámetros. En base a este valor el teclado lleva a cabo una de las siguientes acciones:
- Si el código es
KEYCODE_DELETE, se elimina un carácter a la izquierda del cursor usando el métododeleteSurroundingText. - Si el código es
KEYCODE_DONE, se ejecuta un evento de teclaKEYCODE_ENTER. - Si el código es
KEYCODE_SHIFT, el valor de la variablecapses modificado y el estado de la tecla shift del teclado se actualiza usando el métodosetShifted. El teclado necesita volver a dibujarse cuando el estado cambie para que las etiquetas de las teclas se actualicen. El métodoinvalidateAllKeysse usa para volver a dibujar todas las teclas. - Para el resto de los códigos, cada uno se convierte a un carácter y se envía al campo de entrada. Si el código representa una letra del alfabeto y la variable
capstiene el valortrue, entonces el carácter se convierte a mayúsculas.
Actualiza el método onKey para que se vea de esta forma:
1 |
@Override
|
2 |
public void onKey(int primaryCode, int[] keyCodes) { |
3 |
InputConnection ic = getCurrentInputConnection(); |
4 |
playClick(primaryCode); |
5 |
switch(primaryCode){ |
6 |
case Keyboard.KEYCODE_DELETE : |
7 |
ic.deleteSurroundingText(1, 0); |
8 |
break; |
9 |
case Keyboard.KEYCODE_SHIFT: |
10 |
caps = !caps; |
11 |
keyboard.setShifted(caps); |
12 |
kv.invalidateAllKeys(); |
13 |
break; |
14 |
case Keyboard.KEYCODE_DONE: |
15 |
ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)); |
16 |
break; |
17 |
default: |
18 |
char code = (char)primaryCode; |
19 |
if(Character.isLetter(code) && caps){ |
20 |
code = Character.toUpperCase(code); |
21 |
}
|
22 |
ic.commitText(String.valueOf(code),1); |
23 |
}
|
24 |
}
|
8. Probando el teclado
El teclado de pantalla ya está listo para ser probado. Compila y ejecútalo en un dispositivo Android. Esta aplicación no tiene una Activity, lo que significa que no aparecerá en el lanzador. Para usarla primero debe ser activada en la Configuración del dispositivo.



Después de activar Simple IME, abre cualquier aplicación que permita la entrada de texto (por ejemplo, cualquier aplicación de mensajería) y haz clic en uno de sus campos de entrada. Deberás ver un icono de teclado que aparece en el área de notificaciones. Dependiendo de tu dispositivo, puedes hacer clic en ese icono o arrastrar la barra de notificaciones hacia abajo y seleccionar Simple IME como método de entrada. Ahora podrás escribir usando tu nuevo teclado.



Conclusión
En este tutorial aprendiste a crear una aplicación de teclado personalizado desde cero. Para cambiar la apariencia de tu teclado, lo único que tienes que hacer es agregar estilo adicional a los archivos res/layout/keyboard.xml y res/layout/preview.xml. Para cambiar la posición de las teclas, actualiza el archivo res/xml/qwerty.xml. Para añadir más características a tu teclado, consulta la documentación para desarrolladores.



