1. Code
  2. Coding Fundamentals
  3. Tools

Crea un teclado personalizado en Android

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.
Scroll to top

Spanish (Español) translation by Ana Paulina Figueroa (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

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 valor left o right. 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 valor true, 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 en true para 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 KeyboardView haciendo referencia a la vista definida en el diseño
  • Una instancia de Keyboard que se asigna a KeyboardView
  • Una boolean que 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:

  • commitText para añadir uno o más caracteres al campo de entrada
  • deleteSurroundingText para borrar uno o más caracteres del campo de entrada
  • sendKeyEvent para enviar eventos, como KEYCODE_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étodo deleteSurroundingText.
  • Si el código es KEYCODE_DONE, se ejecuta un evento de tecla KEYCODE_ENTER.
  • Si el código es KEYCODE_SHIFT, el valor de la variable caps es modificado y el estado de la tecla shift del teclado se actualiza usando el método setShifted. El teclado necesita volver a dibujarse cuando el estado cambie para que las etiquetas de las teclas se actualicen. El método invalidateAllKeys se 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 caps tiene el valor true, 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.