29/06/2014
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».
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
- actionSearch
- actionSend
- actionDone
- actionNext
- actionPrevious
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:
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.