android studio - Cerrar / ocultar el teclado suave de Android




15 Answers

Para ayudar a aclarar esta locura, me gustaría comenzar disculpándome en nombre de todos los usuarios de Android por el trato absolutamente ridículo de Google del teclado suave. 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á diseñada horriblemente. No se me ocurre ninguna forma educada de decirlo.

Quiero ocultar el teclado. Espero proporcionar a Android la siguiente declaración: Keyboard.hide() . El fin. Muchas gracias. Pero Android tiene un problema. Debe usar el InputMethodManager para ocultar el teclado. Bien, esta es la API de Android para el teclado. ¡PERO! Debe 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 ni necesidad de ningún Context . o Y, lo que es peor, el IMM requiere que especifique qué View (o, peor aún, qué Window ) quiere ocultar el teclado.

Esto es lo que hace tan difícil ocultar el teclado. Estimado Google: Cuando estoy buscando la receta de un pastel, no hay ningún RecipeProvider de RecipeProvider en la Tierra que se niegue a proporcionarme la receta a menos que primero responda QUIÉN se comerá el pastel ¡Y dónde se lo comerá!

Esta triste historia termina con la fea verdad: para ocultar el teclado de Android, se le solicitará que proporcione 2 formas de identificación: un Context y una View o una Window .

He creado un método de utilidad estática que puede hacer el trabajo MUY sólidamente, siempre que lo llame desde una 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 una Activity ! El método anterior llama a getCurrentFocus de la Activity destino para obtener el token de ventana adecuado.

¿Pero suponga que desea ocultar el teclado de un EditText alojado en un DialogFragment ? No puedes usar el método anterior para eso:

hideKeyboard(getActivity()); //won't work

Esto no funcionará porque pasará una referencia a la Activity host del Fragment , que no tendrá un control enfocado mientras se muestre el Fragment . ¡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 se incluye información adicional obtenida de más tiempo desperdiciado buscando esta solución:

Acerca de windowSoftInputMode

Hay otro punto de discusión que hay que tener en cuenta. De forma predeterminada, Android asignará automáticamente el enfoque inicial al primer texto de EditText o control EditText en su Activity . Naturalmente, se sigue que InputMethod (normalmente el teclado virtual) responderá al evento de enfoque mostrándose a sí mismo. El atributo windowSoftInputMode en AndroidManifest.xml , cuando se establece en stateAlwaysHidden , indica al teclado que ignore este enfoque inicial asignado automáticamente.

<activity
    android:name=".MyActivity"
    android:windowSoftInputMode="stateAlwaysHidden"/>

Casi increíblemente, parece que no hace nada para evitar que el teclado se abra cuando toca el control (a menos que se asignen al control focusable="false" y / o focusableInTouchMode="false" ). Aparentemente, la configuración windowSoftInputMode se aplica solo a los eventos de enfoque automático, no a los eventos activados por eventos táctiles.

Por lo tanto, stateAlwaysHidden está MUY pobremente llamado. Tal vez debería llamarse ignoreInitialFocus en 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); Estos no se refieren explícitamente a su actividad.

Dentro de una clase de fragmentos:

view = getView().getRootView().getWindowToken();

Dado un fragmento de 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: Desactive el enfoque 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();

hide keyboard

Tengo un texto de EditText y un Button en mi diseño.

Después de escribir en el campo de edición y hacer clic en el Button , quiero ocultar el teclado virtual. Supongo que este es un simple código, pero ¿dónde puedo encontrar un ejemplo?




También es útil para ocultar el teclado suave:

getWindow().setSoftInputMode(
    WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN
);

Esto se puede usar para suprimir el teclado virtual hasta que el usuario realmente toque la vista editText.




La solución de Meier también funciona para mí. En mi caso, el nivel superior de mi aplicación es un tabHost y quiero ocultar la palabra clave al cambiar de pestaña: obtengo el token de la ventana desde la vista tabHost.

tabHost.setOnTabChangedListener(new OnTabChangeListener() {
    public void onTabChanged(String tabId) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(tabHost.getApplicationWindowToken(), 0);
    }
}



Actualización: no sé por qué esta solución ya no funciona (acabo de probar en Android 23). Por favor usa la solución de Saurabh Pareek en su lugar. Aquí está:

InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
//Hide:
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
//Show
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

Respuesta antigua:

//Show soft-keyboard:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
//hide keyboard :
 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);



Si todas las otras respuestas aquí no funcionan para usted como le gustaría, hay otra manera de controlar el teclado manualmente.

Cree una función con la que administrará algunas de las propiedades de EditText :

public void setEditTextFocus(boolean isFocused) {
    searchEditText.setCursorVisible(isFocused);
    searchEditText.setFocusable(isFocused);
    searchEditText.setFocusableInTouchMode(isFocused);

    if (isFocused) {
        searchEditText.requestFocus();
    }
}

Luego, asegúrese de que en Foco del texto de EditText abra / cierre el teclado:

searchEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (v == searchEditText) {
            if (hasFocus) {
                // Open keyboard
                ((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(searchEditText, InputMethodManager.SHOW_FORCED);
            } else {
                // Close keyboard
                ((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(searchEditText.getWindowToken(), 0);
            }
        }
    }
});

Ahora, cuando quieras abrir el teclado manualmente llama:

setEditTextFocus(true);

Y para cierre de convocatoria:

setEditTextFocus(false);



De tanto buscar, aquí encontré una respuesta que me funciona.

// Show soft-keyboard:
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);

// Hide soft-keyboard:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);



Esto debería funcionar:

public class KeyBoard {

    public static void show(Activity activity){
        InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY); // show
    }

    public static void hide(Activity activity){
        InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0); // hide
    }

    public static void toggle(Activity activity){
        InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
        if (imm.isActive()){
            hide(activity); 
        } else {
            show(activity); 
        }
    }
}

KeyBoard.toggle(activity);



public void setKeyboardVisibility(boolean show) {
    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    if(show){
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
    }else{
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);
    }
}



Como alternativa a esta solución general , si desea cerrar el teclado virtual desde cualquier lugar sin tener una referencia al campo (Editar Texto) que se usó para abrir el teclado, pero aún así quería hacerlo si el campo estaba enfocado, podría usar esto (de una actividad):

if (getCurrentFocus() != null) {
    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}



Las respuestas anteriores funcionan para diferentes escenarios, pero si desea ocultar el teclado dentro de una vista y tener dificultades para obtener el contexto correcto, intente esto:

setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        hideSoftKeyBoardOnTabClicked(v);
    }
}

private void hideSoftKeyBoardOnTabClicked(View v) {
    if (v != null && context != null) {
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(v.getApplicationWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}

y para obtener el contexto, obténgalo del constructor :)

public View/RelativeLayout/so and so (Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.context = context;
    init();
}



Así es como lo haces en Mono para Android (AKA MonoDroid)

InputMethodManager imm = GetSystemService (Context.InputMethodService) as InputMethodManager;
if (imm != null)
    imm.HideSoftInputFromWindow (searchbox.WindowToken , 0);



Añadir a su actividad android:windowSoftInputMode="stateHidden"en el archivo de manifiesto. Ejemplo:

<activity
            android:name=".ui.activity.MainActivity"
            android:label="@string/mainactivity"
            android:windowSoftInputMode="stateHidden"/>



Para mi caso, estaba usando un SearchView en la barra de acción. Después de que un usuario realiza una búsqueda, el teclado se abrirá de nuevo.

El uso de InputMethodManager no cerró el teclado. Tuve que borrar Foco y establecer el enfoque de la vista de búsqueda en falso:

mSearchView.clearFocus();
mSearchView.setFocusable(false);



En algunos casos, este método puede funcionar excepto de todos los demás. Esto me salva el día :)

public static void hideSoftKeyboard(Activity activity) {
    if (activity != null) {
        InputMethodManager inputManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (activity.getCurrentFocus() != null && inputManager != null) {
            inputManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
            inputManager.hideSoftInputFromInputMethod(activity.getCurrentFocus().getWindowToken(), 0);
        }
    }
}

public static void hideSoftKeyboard(View view) {
    if (view != null) {
        InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputManager != null) {
            inputManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
    }
}



Solo usa este código optimizado en tu actividad:

if (this.getCurrentFocus() != null) {
    InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
    inputManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}



Related

android android-layout android-softkeyboard android-input-method soft-keyboard