Tip Android #34: Personalizar el teclado con imeOptions

29/06/2014
android tip

El widget EditText permite la definición de un botón de acción en el teclado que aporta una pequeña personalización del mismo y que reemplaza el botón «return».

default

IMPORTANTE: esta funcionalidad no está disponible en todos los dispositivos con Android (por ejemplo HTC Desire) por lo que siempre debe ser algo accesorio y nunca imprescindible para la correcta utilización de la aplicación.

Por defecto, y siempre y cuando se haya definido el atributo android:inputType, si tenemos varios EditText el botón de acción tendrá el valor Next y nos llevará al siguiente EditText, mientras que si sólo tenemos un EditText o tenemos varios y estamos en el último, se establecerá la acción «Done» (Ok). Este comportamiento se puede personalizar definiendo el atributo android:imeOptions, los valores más interesantes que podemos utilizar son:

  • actionNone: deshabilita el comportamiento por defecto y el botón de acción muestra «return».
  • actionGo go
  • actionSearch search
  • actionSend send
  • actionDone done
  • actionNext next
  • actionPrevious prev

IMPORTANTE: A partir de Android 4, y según el dispositivo, si se mantiene pulsado el botón de acción, Android mostrará la acción por defecto, por ejemplo:

android-ime action

Para hacer una prueba usemos el siguiente layout con un par de EditText.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/send"
        android:imeOptions="actionSend"
        android:inputType="text"> 
                       
    </EditText>
    
    <EditText
        android:id="@+id/editText2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/search"
        android:imeOptions="actionSearch"
        android:inputType="text">          
    </EditText>
  
</LinearLayout>

Una vez definida la opción sólo resta implementar el listener que responda a su pulsación. Asimismo, en ocasiones necesitaremos también ocultar el teclado tal y como se hace en el ejemplo.

package com.danielme.tipsandroid.imeoptions;

import com.danieme.tipsandroid.imeoptions.R;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.TextView.OnEditorActionListener;

/**
 * 
 * @author danielme.com
 * 
 */
public class MainActivity extends Activity
{

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		EditText sendEditText = (EditText) findViewById(R.id.editText1);
		
		//set focus and show keyboard
		sendEditText.requestFocus();
		getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
		
		sendEditText.setOnEditorActionListener(new OnEditorActionListener() {
			@Override
			public boolean onEditorAction(TextView textView, int actionId, KeyEvent event)
			{
				boolean action = false;
				if (actionId == EditorInfo.IME_ACTION_SEND)
				{
					// hide keyboard
					InputMethodManager inputMethodManager = (InputMethodManager) textView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
					inputMethodManager.hideSoftInputFromWindow(textView.getWindowToken(), 0);

					Toast.makeText(MainActivity.this, R.string.send, Toast.LENGTH_SHORT).show();
					action = true;
				}
				return action;
			}
		});
		
		EditText searchEditText = (EditText) findViewById(R.id.editText2);
		searchEditText.setOnEditorActionListener(new OnEditorActionListener()
		{
			@Override
			public boolean onEditorAction(TextView textView, int actionId, KeyEvent event)
			{
				boolean action = false;
				if (actionId == EditorInfo.IME_ACTION_SEARCH)
				{
					//hide keyboard
					InputMethodManager inputMethodManager = (InputMethodManager) textView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
					inputMethodManager.hideSoftInputFromWindow(textView.getWindowToken(), 0);
					
					Toast.makeText(MainActivity.this, R.string.search, Toast.LENGTH_SHORT).show();
					action = true;
				}
				return action;
			}
		});		

	}
}

Si las acciones predefinidas no se adecuan a nuestras necesidades, podemos definir una personalizada indicando directamente al EditText su texto y un identificador que usaremos en el listener. Por ejemplo:

<EditText
        android:id="@+id/editText3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/custom"
        android:imeActionId="@+id/action_custom"
        android:imeActionLabel="@string/custom"
        android:inputType="text">          
    </EditText>

Sin embargo, el id definido para la acción no siempre funciona y en su lugar el id recibido es el 0, correspondiente a la acción EditorInfo.IME_ACTION_UNSPECIFIED, por lo que resulta conveniente tenerlo en cuenta al implementar el listener.

EditText customEditText = (EditText) findViewById(R.id.editText3);
		customEditText.setOnEditorActionListener(new OnEditorActionListener()
		{
			@Override
			public boolean onEditorAction(TextView textView, int actionId, KeyEvent event)
			{
				boolean action = false;
				if (actionId == R.id.action_custom || actionId == EditorInfo.IME_ACTION_UNSPECIFIED)
				{
					//hide keyboard
					InputMethodManager inputMethodManager = (InputMethodManager) textView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
					inputMethodManager.hideSoftInputFromWindow(textView.getWindowToken(), 0);
					
					Toast.makeText(MainActivity.this, R.string.custom, Toast.LENGTH_SHORT).show();
					action = true;
				}
				return action;
			}
		});		

Por último, comentar que en este ejemplo concreto no es necesario definir un listener «anónimo» para cada EditText y se podría implementar un único listener para abstraer mejor el código:

package com.danielme.tipsandroid.imeoptions;

import com.danieme.tipsandroid.imeoptions.R;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.TextView.OnEditorActionListener;

/**
 * 
 * @author danielme.com
 * 
 */
public class MainActivity extends Activity
{

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		EditText sendEditText = (EditText) findViewById(R.id.editText1);

		// set focus and show keyboard
		sendEditText.requestFocus();
		getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
 
		sendEditText.setOnEditorActionListener(new MainActivityOnEditorActionListener());			
		EditText searchEditText = (EditText) findViewById(R.id.editText2);
		searchEditText.setOnEditorActionListener(new MainActivityOnEditorActionListener());
		EditText customEditText = (EditText) findViewById(R.id.editText3);
		customEditText.setOnEditorActionListener(new MainActivityOnEditorActionListener());		

	}

	class MainActivityOnEditorActionListener implements OnEditorActionListener
	{
		@Override
		public boolean onEditorAction(TextView textView, int actionId, KeyEvent event)
		{
			boolean action = false;
			int stringId = -1;
			switch (actionId)
			{
				case EditorInfo.IME_ACTION_SEND:
					stringId = R.string.send;
					break;
				case EditorInfo.IME_ACTION_SEARCH:
					stringId = R.string.search;
					break;
				case R.id.action_custom:
				case EditorInfo.IME_ACTION_UNSPECIFIED:
					stringId = R.string.custom;
					break;
				default:
					break;
			}
			if (stringId != -1)
			{
				// hide keyboard
				InputMethodManager inputMethodManager = (InputMethodManager) textView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
				inputMethodManager.hideSoftInputFromWindow(textView.getWindowToken(), 0);

				Toast.makeText(MainActivity.this, stringId, Toast.LENGTH_SHORT).show();
				action = true;
			}
			return action;
		}

	}
}

El proyecto completo para Eclipse ADT se encuentra en Github. Para más información sobre cómo utilizar GitHub, consultar este artículo.

<< TIPS ANDROID

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.