Para ayudar a aclarar esta locura, me gustaría comenzar disculpándome en nombre de todos los usuarios de Android por el tratamiento absolutamente ridículo del teclado suave de Google. La razón por la que hay tantas respuestas, cada una diferente, para la misma pregunta simple es porque esta API, como muchas otras en Android, está terriblemente diseñada. No se me ocurre ninguna forma cortés de decirlo.
Quiero esconder el teclado Espero para proporcionar Android con la siguiente afirmación: Keyboard.hide()
. El fin. Muchas gracias. Pero Android tiene un problema. Debe usar el InputMethodManager
para ocultar el teclado. OK, bien, esta es la API de Android para el teclado. ¡PERO! Debes tener un Context
para poder acceder al IMM. Ahora tenemos un problema. Es posible que desee ocultar el teclado de una clase estática o de utilidad que no tiene uso o necesidad de ninguna Context
. o Y MUCHO peor, el IMM requiere que especifique de qué View
(o peor aún, de qué Window
) quiere ocultar el teclado.
Esto es lo que hace que ocultar el teclado sea tan desafiante. Estimado Google: ¡Cuando busco la receta de un pastel, no hay nadie RecipeProvider
en la Tierra que se niegue a proporcionarme la receta a menos que responda primero a QUIÉN se comerá el pastel Y dónde se comerá!
Esta triste historia termina con la fea verdad: para ocultar el teclado de Android, deberá proporcionar 2 formas de identificación: a Context
y a View
o a Window
.
He creado un método de utilidad estática que puede hacer el trabajo MUY sólidamente, siempre que lo llame desde un Activity
.
public static void hideKeyboard(Activity activity) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
//Find the currently focused view, so we can grab the correct window token from it.
View view = activity.getCurrentFocus();
//If no view currently has focus, create a new one, just so we can grab a window token from it
if (view == null) {
view = new View(activity);
}
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Tenga en cuenta que este método de utilidad SOLO funciona cuando se llama desde un Activity
! El método anterior llama getCurrentFocus
al objetivo Activity
para obtener el token de ventana adecuado.
Pero supongamos que desea ocultar el teclado de un EditText
host en un DialogFragment
? No puede usar el método anterior para eso:
hideKeyboard(getActivity()); //won't work
¡Esto no funcionará porque pasará una referencia al Fragment
host del sistema Activity
, que no tendrá control enfocado mientras Fragment
se muestra! ¡Guauu! Entonces, para ocultar el teclado de los fragmentos, recurro al nivel inferior, más común y más feo:
public static void hideKeyboardFrom(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
A continuación hay información adicional obtenida de más tiempo perdido persiguiendo esta solución:
Acerca de windowSoftInputMode
Hay otro punto de contención a tener en cuenta. Por defecto, Android asignará automáticamente el foco inicial al primer EditText
control enfocable en su Activity
. Naturalmente, se deduce que InputMethod (generalmente el teclado virtual) responderá al evento de enfoque mostrándose. El windowSoftInputMode
atributo en AndroidManifest.xml
, cuando se establece en stateAlwaysHidden
, indica al teclado que ignore este foco inicial asignado automáticamente.
<activity
android:name=".MyActivity"
android:windowSoftInputMode="stateAlwaysHidden"/>
Casi increíblemente, parece no hacer nada para evitar que el teclado se abra cuando se toca el control (a menos que focusable="false"
y / o focusableInTouchMode="false"
están asignados al control). Aparentemente, la configuración windowSoftInputMode se aplica solo a eventos de enfoque automático, no a eventos de enfoque activados por eventos táctiles.
Por lo tanto, stateAlwaysHidden
es MUY mal nombrado. Quizás debería llamarse en su ignoreInitialFocus
lugar.
Espero que esto ayude.
ACTUALIZACIÓN: más formas de obtener un token de ventana
Si no hay una vista enfocada (por ejemplo, puede suceder si acaba de cambiar fragmentos), hay otras vistas que proporcionarán un token de ventana útil.
Estas son alternativas para el código anterior. if (view == null) view = new View(activity);
No se refieren explícitamente a su actividad.
Dentro de una clase de fragmento:
view = getView().getRootView().getWindowToken();
Dado un fragmento fragment
como parámetro:
view = fragment.getView().getRootView().getWindowToken();
A partir de su cuerpo de contenido:
view = findViewById(android.R.id.content).getRootView().getWindowToken();
ACTUALIZACIÓN 2: enfoque claro para evitar mostrar el teclado nuevamente si abre la aplicación desde el fondo
Agregue esta línea al final del método:
view.clearFocus();