Cerrar / ocultar el teclado suave de Android


Answers

Para ayudar a aclarar esta locura, me gustaría comenzar pidiendo disculpas en nombre de todos los usuarios de Android por el tratamiento francamente 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á horriblemente diseñada. No puedo pensar en una forma educada de decirlo.

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

Esto es lo que hace que esconder el teclado sea tan desafiante. Querido Google: Cuando busco la receta de un pastel, no hay ningún RecipeProvider en la Tierra que se niegue a proporcionarme la receta, a menos que primero responda ¿QUIÉN se va a comer el pastel Y dónde será comido?

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

Creé un método de utilidad estático que puede hacer el trabajo MUY sólidamente, siempre que lo llames 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 SÓLO funciona cuando se lo llama desde una Activity ! El método anterior llama a getCurrentFocus de la Activity destino para obtener el token de ventana adecuado.

Pero supongamos que quiere ocultar el teclado de un EditText alojado en un DialogFragment ? No puede usar el método anterior para eso:

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

Esto no funcionará porque pasarás una referencia a la Activity anfitrión del Fragment , que no tendrá control enfocado mientras se muestra el Fragment . ¡Guauu! Entonces, para esconder 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 encuentra información adicional obtenida de más tiempo perdido persiguiendo esta solución:

Acerca de WindowSoftInputMode

Todavía hay otro punto de discordia que debe tenerse en cuenta. De forma predeterminada, Android asignará automáticamente el foco inicial al primer EditText o control EditText en su Activity . Naturalmente, se deduce que InputMethod (por lo general, 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 al tocar el control (a menos que focusable="false" y / focusableInTouchMode="false" estén asignados al control). Aparentemente, la configuración windowSoftInputMode se aplica solo a los eventos de enfoque automático, no a los eventos de enfoque activados desde eventos táctiles.

Por lo tanto, stateAlwaysHidden es MUY mal llamado en verdad. Quizás 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 los 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 fragmento:

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

Dado un fragmento de fragment como parámetro:

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

A partir de tu 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();

Question

Tengo un 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 se trata de una simple pieza de código, pero ¿dónde puedo encontrar un ejemplo?




La respuesta corta

En su oyente OnClick llame al onEditorAction de EditText con IME_ACTION_DONE

button.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        someEditText.onEditorAction(EditorInfo.IME_ACTION_DONE)
    }
});

El desglose

Siento que este método es mejor, más simple y más alineado con el patrón de diseño de Android. En el ejemplo simple anterior (y generalmente en la mayoría de los casos comunes) tendrás un EditText que tiene / tenía el foco y también usualmente era el que invocó el teclado en primer lugar (definitivamente es capaz de invocarlo en muchos escenarios comunes). De la misma manera, debería ser el que suelte el teclado, generalmente eso se puede hacer con una ImeAction . Simplemente vea cómo se EditText con android:imeOptions="actionDone" , quiere lograr el mismo comportamiento por el mismo medio.

Verifique esta respuesta relacionada




This worked for me for all the bizarre keyboard behavior

private boolean isKeyboardVisible() {
    Rect r = new Rect();
    //r will be populated with the coordinates of your view that area still visible.
    mRootView.getWindowVisibleDisplayFrame(r);

    int heightDiff = mRootView.getRootView().getHeight() - (r.bottom - r.top);
    return heightDiff > 100; // if more than 100 pixels, its probably a keyboard...
}

protected void showKeyboard() {
    if (isKeyboardVisible())
        return;
    InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    if (getCurrentFocus() == null) {
        inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
    } else {
        View view = getCurrentFocus();
        inputMethodManager.showSoftInput(view, InputMethodManager.SHOW_FORCED);
    }
}

protected void hideKeyboard() {
    if (!isKeyboardVisible())
        return;
    InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    View view = getCurrentFocus();
    if (view == null) {
        if (inputMethodManager.isAcceptingText())
            inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);
    } else {
        if (view instanceof EditText)
            ((EditText) view).setText(((EditText) view).getText().toString()); // reset edit text bug on some keyboards bug
        inputMethodManager.hideSoftInputFromInputMethod(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}



Tengo una solución más para ocultar el teclado:

InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);

Aquí pase HIDE_IMPLICIT_ONLY en la posición de showFlag y 0 en la posición de hiddenFlag . Cerrará con fuerza el teclado suave.




protected void hideSoftKeyboard(EditText input) {
    input.setInputType(0);
    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(input.getWindowToken(), 0);    
}



Saurabh Pareek tiene la mejor respuesta hasta el momento.

Aunque también podría usar las banderas correctas.

/* hide keyboard */
((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
    .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

/* show keyboard */
((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
    .toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);

Ejemplo de uso real

/* click button */
public void onClick(View view) {      
  /* hide keyboard */
  ((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
      .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);

  /* start loader to check parameters ... */
}

/* loader finished */
public void onLoadFinished(Loader<Object> loader, Object data) {
    /* parameters not valid ... */

    /* show keyboard */
    ((InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE))
        .toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY);

    /* parameters valid ... */
}



Thanks to this SO answer , I derived the following which, in my case, works nicely when scrolling through the the fragments of a ViewPager...

private void hideKeyboard() {   
    // Check if no view has focus:
    View view = this.getCurrentFocus();
    if (view != null) {
        InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}

private void showKeyboard() {   
    // Check if no view has focus:
    View view = this.getCurrentFocus();
    if (view != null) {
        InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
    }
}



Tengo el caso, donde mi EditTextpuede estar ubicado también en una AlertDialog, por lo que el teclado debe cerrarse al cerrar. El siguiente código parece estar funcionando en cualquier lugar:

public static void hideKeyboard( Activity activity ) {
    InputMethodManager imm = (InputMethodManager)activity.getSystemService( Context.INPUT_METHOD_SERVICE );
    View f = activity.getCurrentFocus();
    if( null != f && null != f.getWindowToken() && EditText.class.isAssignableFrom( f.getClass() ) )
        imm.hideSoftInputFromWindow( f.getWindowToken(), 0 );
    else 
        activity.getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN );
}



Como alternativa a esta solución general , si quisiera cerrar el teclado virtual desde cualquier lugar sin tener una referencia al campo (Editar texto) que se utilizó 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);
}



Just use this optimized code in your activity:

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



If you want to close the soft keyboard during a unit or functional test, you can do so by clicking the "back button" from your test:

// Close the soft keyboard from a Test
getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);

I put "back button" in quotes, since the above doesn't trigger the onBackPressed() for the Activity in question. It just closes the keyboard.

Make sure to pause for a little while before moving on, since it takes a little while to close the back button, so subsequent clicks to Views, etc., won't be registered until after a short pause (1 second is long enough ime).




For my case, I was using the a SearchView in the actionbar. After a user performs a search, the keyboard would pop open again.

Using the InputMethodManager did not close the keyboard. I had to clearFocus and set the focusable of the search view to false:

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



Por favor intente este código a continuación en oncreate ()

EditText edtView = (EditText) findViewById (R.id.editTextConvertValue); edtView.setInputType (0);




Estoy usando un teclado personalizado para ingresar un número hexadecimal, por lo que no puedo mostrar el teclado IMM ...

En v3.2.4_r1 se agregó setSoftInputShownOnFocus(boolean show) para controlar el clima o no mostrar el teclado cuando un TextView obtiene el foco, pero aún está oculto, por lo que se debe usar el reflejo:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
    try {
        Method method = TextView.class.getMethod("setSoftInputShownOnFocus", boolean.class);
        method.invoke(mEditText, false);
    } catch (Exception e) {
        // Fallback to the second method
    }
}

Para versiones anteriores, obtuve muy buenos resultados (pero lejos de ser perfecto) con un OnGlobalLayoutListener , agregado con la ayuda de un ViewTreeObserver desde mi vista raíz y luego comprobando si el teclado se muestra así:

@Override
public void onGlobalLayout() {
    Configuration config = getResources().getConfiguration();

    // Dont allow the default keyboard to show up
    if (config.keyboardHidden != Configuration.KEYBOARDHIDDEN_YES) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mRootView.getWindowToken(), 0);
    }
}

Esta última solución puede mostrar el teclado por una fracción de segundo y estropea los controles de selección.

Cuando en el teclado ingresa a pantalla completa, no se llama a GlobalBayout. Para evitar eso, use TextView#setImeOptions(int) o en la declaración TextView XML:

android:imeOptions="actionNone|actionUnspecified|flagNoFullscreen|flagNoExtractUi"

Actualización: Acabo de encontrar lo que los diálogos usan para nunca mostrar el teclado y funciona en todas las versiones:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
        WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);



Simple and Easy to use method, just call hideKeyboardFrom(YourActivity.this); to hide keyboard

/**
 * This method is used to hide keyboard
 * @param activity
 */
public static void hideKeyboardFrom(Activity activity) {
    InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}



Links