windowsoftinputmode studio close android android-softkeyboard

close - hide keyboard android studio



¿Cómo ocultar el teclado virtual en Android después de hacer clic fuera de EditText? (30)

Ok, todo el mundo sabe que para ocultar un teclado necesitas implementar:

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);

Pero el problema aquí es cómo ocultar el teclado cuando el usuario toca o selecciona cualquier otro lugar que no sea un EditText o el SoftKeyboard.

Intenté usar onTouchEvent() en mi Activity principal, pero eso solo funciona si el usuario toca fuera de cualquier otra vista y no hay vista de desplazamiento.

Traté de implementar un toque, clic, enfoque de escucha sin ningún éxito.

Incluso intenté implementar mi propia vista de desplazamiento para interceptar eventos táctiles, pero solo puedo obtener las coordenadas del evento y no la vista pulsada.

¿Hay una manera estándar de hacer esto? En iPhone fue muy fácil.


Actividad

@Override public boolean dispatchTouchEvent(MotionEvent ev) { ScreenUtils.hideKeyboard(this, findViewById(android.R.id.content).getWindowToken()); return super.dispatchTouchEvent(ev); }

ScreenUtils

public static void hideKeyboard(Context context, IBinder windowToken) { InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS); }


Aquí hay otra variación en la respuesta de fje que aborda las cuestiones planteadas por sosite.

La idea aquí es manejar las acciones hacia abajo y hacia arriba en el método dispatchTouchEvent la Actividad. En la acción hacia abajo, tomamos nota de la vista enfocada actualmente (si existe) y si el toque estaba dentro de ella, guardando los dos bits de información para más adelante.

En la acción hacia arriba, primero enviamos, para permitir que otra vista potencialmente se enfoque. Si después de eso, la vista enfocada actualmente es la vista enfocada originalmente, y el toque hacia abajo estaba dentro de esa vista, entonces dejamos el teclado abierto.

Si la vista enfocada actualmente es diferente a la vista enfocada originalmente y es un texto de EditText , entonces también dejamos el teclado abierto.

De lo contrario lo cerramos.

Entonces, para resumir, esto funciona de la siguiente manera:

  • al tocar dentro de un EditText enfocado actualmente, el teclado permanece abierto
  • al pasar de un EditText enfocado a otro EditText , el teclado permanece abierto (no se cierra / vuelve a abrir)
  • al tocar en cualquier lugar fuera de un EditText enfocado actualmente que no sea otro EditText , el teclado se cierra
  • cuando se presiona EditText un EditText de EditText para abrir la barra de acción contextual (con los botones cortar / copiar / pegar), el teclado permanece abierto, aunque la acción ARRIBA tuvo lugar fuera del texto de EditText enfocado (que se movió hacia abajo para dejar espacio para la TAXI). Tenga en cuenta, sin embargo, que cuando toca un botón en el CAB, cerrará el teclado. Eso puede o no ser deseable; Si quieres cortar / copiar desde un campo y pegar en otro, sería. Si desea volver a pegar en el mismo EditText , no lo sería.
  • cuando el EditText enfocado está en la parte inferior de la pantalla y hace un clic largo en un texto para seleccionarlo, el EditText mantiene enfocado y, por lo tanto, el teclado se abre como usted quiere, porque hacemos clic en "tocar está dentro de los límites de la vista" acción hacia abajo, no la acción hacia arriba.

    private View focusedViewOnActionDown; private boolean touchWasInsideFocusedView; @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: focusedViewOnActionDown = getCurrentFocus(); if (focusedViewOnActionDown != null) { final Rect rect = new Rect(); final int[] coordinates = new int[2]; focusedViewOnActionDown.getLocationOnScreen(coordinates); rect.set(coordinates[0], coordinates[1], coordinates[0] + focusedViewOnActionDown.getWidth(), coordinates[1] + focusedViewOnActionDown.getHeight()); final int x = (int) ev.getX(); final int y = (int) ev.getY(); touchWasInsideFocusedView = rect.contains(x, y); } break; case MotionEvent.ACTION_UP: if (focusedViewOnActionDown != null) { // dispatch to allow new view to (potentially) take focus final boolean consumed = super.dispatchTouchEvent(ev); final View currentFocus = getCurrentFocus(); // if the focus is still on the original view and the touch was inside that view, // leave the keyboard open. Otherwise, if the focus is now on another view and that view // is an EditText, also leave the keyboard open. if (currentFocus.equals(focusedViewOnActionDown)) { if (touchWasInsideFocusedView) { return consumed; } } else if (currentFocus instanceof EditText) { return consumed; } // the touch was outside the originally focused view and not inside another EditText, // so close the keyboard InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( focusedViewOnActionDown.getWindowToken(), 0); focusedViewOnActionDown.clearFocus(); return consumed; } break; } return super.dispatchTouchEvent(ev); }


Bueno, me las arreglé para resolver un poco el problema, anulé el dispatchTouchEvent en mi actividad, allí estoy usando lo siguiente para ocultar el teclado.

/** * Called to process touch screen events. */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: touchDownTime = SystemClock.elapsedRealtime(); break; case MotionEvent.ACTION_UP: //to avoid drag events if (SystemClock.elapsedRealtime() - touchDownTime <= 150){ EditText[] textFields = this.getFields(); if(textFields != null && textFields.length > 0){ boolean clickIsOutsideEditTexts = true; for(EditText field : textFields){ if(isPointInsideView(ev.getRawX(), ev.getRawY(), field)){ clickIsOutsideEditTexts = false; break; } } if(clickIsOutsideEditTexts){ this.hideSoftKeyboard(); } } else { this.hideSoftKeyboard(); } } break; } return super.dispatchTouchEvent(ev); }

EDITAR: el método getFields () es solo un método que devuelve una matriz con los campos de texto en la vista. Para evitar crear esta matriz en cada toque, creé una matriz estática llamada sFields, que se devuelve con el método getFields (). Esta matriz se inicializa en los métodos onStart () como:

sFields = new EditText[] {mUserField, mPasswordField};

No es perfecto. El tiempo del evento de arrastre solo se basa en heurísticas, por lo que a veces no se oculta cuando se realizan clics largos, y también terminé creando un método para obtener todos los EditTexts por vista; de lo contrario, el teclado se ocultaría y mostraría al hacer clic en otro EditText.

Aún así, las soluciones más limpias y más cortas son bienvenidas.


El siguiente fragmento simplemente oculta el teclado:

public static void hideSoftKeyboard(Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService( Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( activity.getCurrentFocus().getWindowToken(), 0); }

Puede colocar esto en una clase de utilidad, o si lo está definiendo dentro de una actividad, evite el parámetro de actividad, o llame a hideSoftKeyboard(this) .

La parte más complicada es cuándo llamarlo. Puede escribir un método que itere a través de cada View en su actividad, y verificar si es una instanceof EditText si no está registrado un setOnTouchListener en ese componente y todo caerá en su lugar. En caso de que se esté preguntando cómo hacerlo, de hecho es bastante simple. Esto es lo que hace, escribe un método recursivo como el siguiente, de hecho, puede usar esto para hacer cualquier cosa, como configurar tipos de letra personalizados, etc. Aquí está el método

public void setupUI(View view) { // Set up touch listener for non-text box views to hide keyboard. if (!(view instanceof EditText)) { view.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { hideSoftKeyboard(MyActivity.this); return false; } }); } //If a layout container, iterate over children and seed recursion. if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { View innerView = ((ViewGroup) view).getChildAt(i); setupUI(innerView); } } }

Eso es todo, solo llame a este método después de que haya establecido setContentView en su actividad. En caso de que se esté preguntando qué parámetro pasaría, es el id del contenedor principal. Asigne una id a su contenedor principal como

<RelativeLayoutPanel android:id="@+id/parent"> ... </RelativeLayout>

y llame a setupUI(findViewById(R.id.parent)) , eso es todo.

Si desea usar esto de manera efectiva, puede crear una Activity extendida y poner este método, y hacer que todas las demás actividades en su aplicación extiendan esta actividad y llame a su setupUI() en el método onCreate() .

Espero eso ayude.

Si usa más de 1 actividad, defina un ID común para el diseño principal como <RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout>

Luego extienda una clase de Activity y defina setupUI(findViewById(R.id.main_parent)) dentro de su OnResume() y extienda esta clase en lugar de la actividad `` in your program


Encuentro la respuesta aceptada un poco complicada.

Aquí está mi solución. Agregue un OnTouchListener a su diseño principal, es decir:

findViewById(R.id.mainLayout).setOnTouchListener(this)

y ponga el siguiente código en el método onTouch.

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);

De esta manera no tienes que iterar sobre todas las vistas.


Existe un enfoque más simple, basado en el mismo problema del iPhone. Simplemente anule el diseño del fondo en el evento táctil, donde se encuentra el texto de edición. Simplemente use este código en el OnCreate de la actividad (login_fondo es el diseño de la raíz):

final LinearLayout llLogin = (LinearLayout)findViewById(R.id.login_fondo); llLogin.setOnTouchListener( new OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent ev) { InputMethodManager imm = (InputMethodManager) mActivity.getSystemService( android.content.Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(mActivity.getCurrentFocus().getWindowToken(), 0); return false; } });


He hecho de esta manera:

@Override public boolean dispatchTouchEvent(MotionEvent ev) { View view = getCurrentFocus(); if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText && !view.getClass().getName().startsWith("android.webkit.")) { int scrcoords[] = new int[2]; view.getLocationOnScreen(scrcoords); float x = ev.getRawX() + view.getLeft() - scrcoords[0]; float y = ev.getRawY() + view.getTop() - scrcoords[1]; if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y > view.getBottom()) hideKeyboard(this); } return super.dispatchTouchEvent(ev); }

Ocultar el código del teclado :

public static void hideKeyboard(Activity act) { if(act!=null) ((InputMethodManager)act.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((act.getWindow().getDecorView().getApplicationWindowToken()), 0); }

Hecho


He refinado el método, puse el siguiente código en alguna clase de utilidad de UI (preferiblemente, no necesariamente) para que pueda acceder a él desde todas sus clases de Actividad o Fragmento para cumplir su propósito.

public static void serachAndHideSoftKeybordFromView(View view, final Activity act) { if(!(view instanceof EditText)) { view.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { hideSoftKeyboard(act); return false; } }); } if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { View nextViewInHierarchy = ((ViewGroup) view).getChildAt(i); serachAndHideSoftKeybordFromView(nextViewInHierarchy, act); } } } public static void hideSoftKeyboard (Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0); }

Luego diga por ejemplo que necesita llamarlo desde la actividad, llámelo de la siguiente manera;

UIutils.serachAndHideSoftKeybordFromView(findViewById(android.R.id.content), YourActivityName.this);

darse cuenta

findViewById (android.R.id.content)

Esto nos da la vista raíz del grupo actual (no debe haber configurado el ID en la vista raíz).

Saludos :)


Implementé dispatchTouchEvent en Activity para hacer esto:

private EditText mEditText; private Rect mRect = new Rect(); @Override public boolean dispatchTouchEvent(MotionEvent ev) { final int action = MotionEventCompat.getActionMasked(ev); int[] location = new int[2]; mEditText.getLocationOnScreen(location); mRect.left = location[0]; mRect.top = location[1]; mRect.right = location[0] + mEditText.getWidth(); mRect.bottom = location[1] + mEditText.getHeight(); int x = (int) ev.getX(); int y = (int) ev.getY(); if (action == MotionEvent.ACTION_DOWN && !mRect.contains(x, y)) { InputMethodManager input = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); input.hideSoftInputFromWindow(mEditText.getWindowToken(), 0); } return super.dispatchTouchEvent(ev); }

Y lo he probado, funciona perfecto!



Método para mostrar / ocultar el teclado suave

InputMethodManager inputMethodManager = (InputMethodManager) currentActivity.getSystemService(Context.INPUT_METHOD_SERVICE); if (isShow) { if (currentActivity.getCurrentFocus() == null) { inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } else { inputMethodManager.showSoftInput(currentActivity.getCurrentFocus(), InputMethodManager.SHOW_FORCED); } } else { if (currentActivity.getCurrentFocus() == null) { inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0); } else { inputMethodManager.hideSoftInputFromInputMethod(currentActivity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } }

Espero que hayan sido útiles.


Me gustó el enfoque de llamar dispatchTouchEvent hecho por htafoya, pero:

  • No entendí la parte del temporizador (¿no sé por qué debería ser necesario medir el tiempo de inactividad?)
  • No me gusta registrar / anular el registro de todos los EditTexts con cada cambio de vista (pueden ser muchos cambios de vista y edittexts en jerarquías complejas)

Entonces, hice esta solución algo más fácil:

@Override public boolean dispatchTouchEvent(final MotionEvent ev) { // all touch events close the keyboard before they are processed except EditText instances. // if focus is an EditText we need to check, if the touchevent was inside the focus editTexts final View currentFocus = getCurrentFocus(); if (!(currentFocus instanceof EditText) || !isTouchInsideView(ev, currentFocus)) { ((InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE)) .hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } return super.dispatchTouchEvent(ev); } /** * determine if the given motionevent is inside the given view. * * @param ev * the given view * @param currentFocus * the motion event. * @return if the given motionevent is inside the given view */ private boolean isTouchInsideView(final MotionEvent ev, final View currentFocus) { final int[] loc = new int[2]; currentFocus.getLocationOnScreen(loc); return ev.getRawX() > loc[0] && ev.getRawY() > loc[1] && ev.getRawX() < (loc[0] + currentFocus.getWidth()) && ev.getRawY() < (loc[1] + currentFocus.getHeight()); }

Hay una desventaja:

Cambiar de un EditText a otro EditText hace que el teclado se oculte y vuelva a mostrar, en mi caso, así se desea, porque muestra que se cambió entre dos componentes de entrada.


Modifiqué la solución de Andre Luis IM. Conseguí esta:

Creé un método de utilidad para ocultar el teclado virtual de la misma manera que lo hizo Andre Luiz IM:

public static void hideSoftKeyboard(Activity activity) { InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0); }

Pero en lugar de registrar un OnTouchListener para cada vista, que da un rendimiento pobre, registré el OnTouchListener solo para la vista raíz. Desde que el evento burbujea hasta que se consume (EditText es una de las vistas que lo consume de forma predeterminada), si llega a la vista raíz, es porque no se consumió, por lo que cierro el teclado virtual.

findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Utils.hideSoftKeyboard(activity); return false; } });


Puedes lograr esto haciendo los siguientes pasos:

  1. Haga que la vista principal (vista de contenido de su actividad) se pueda hacer clic y enfocar agregando los siguientes atributos

    android:clickable="true" android:focusableInTouchMode="true"

  2. Implementar un método hideKeyboard ()

    public void hideKeyboard(View view) { InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); }

  3. Por último, configure el onFocusChangeListener de su edittext.

    edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { hideKeyboard(v); } } });

Como se señaló en uno de los comentarios a continuación, esto podría no funcionar si la vista principal es un ScrollView. Para tal caso, se puede agregarInTouchMode seleccionable y seleccionable en la vista directamente debajo de ScrollView.


Reemplace el booleano público dispatchTouchEvent (evento MotionEvent) en cualquier actividad (o extienda la clase de actividad)

@Override public boolean dispatchTouchEvent(MotionEvent event) { View view = getCurrentFocus(); boolean ret = super.dispatchTouchEvent(event); if (view instanceof EditText) { View w = getCurrentFocus(); int scrcoords[] = new int[2]; w.getLocationOnScreen(scrcoords); float x = event.getRawX() + w.getLeft() - scrcoords[0]; float y = event.getRawY() + w.getTop() - scrcoords[1]; if (event.getAction() == MotionEvent.ACTION_UP && (x < w.getLeft() || x >= w.getRight() || y < w.getTop() || y > w.getBottom()) ) { InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0); } } return ret; }

Y eso es todo lo que necesitas hacer.


Soy consciente de que este hilo es bastante antiguo, la respuesta correcta parece válida y hay muchas soluciones de trabajo por ahí, pero creo que el enfoque que se indica a continuación puede tener un beneficio adicional en cuanto a eficiencia y elegancia.

Necesito este comportamiento para todas mis actividades, así que creé una clase CustomActivity heredando de la clase Actividad y "enganché" la función dispatchTouchEvent . Existen principalmente dos condiciones a tener en cuenta:

  1. Si el enfoque no cambia y alguien está tocando fuera del campo de entrada actual, descarte el IME
  2. Si el enfoque ha cambiado y el siguiente elemento enfocado no es una instancia de ningún tipo de campo de entrada, descarte el IME

Este es mi resultado:

@Override public boolean dispatchTouchEvent(MotionEvent ev) { if(ev.getAction() == MotionEvent.ACTION_UP) { final View view = getCurrentFocus(); if(view != null) { final boolean consumed = super.dispatchTouchEvent(ev); final View viewTmp = getCurrentFocus(); final View viewNew = viewTmp != null ? viewTmp : view; if(viewNew.equals(view)) { final Rect rect = new Rect(); final int[] coordinates = new int[2]; view.getLocationOnScreen(coordinates); rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight()); final int x = (int) ev.getX(); final int y = (int) ev.getY(); if(rect.contains(x, y)) { return consumed; } } else if(viewNew instanceof EditText || viewNew instanceof CustomEditText) { return consumed; } final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0); viewNew.clearFocus(); return consumed; } } return super.dispatchTouchEvent(ev); }

Nota al margen: Además, asigno estos atributos a la vista raíz, por lo que es posible despejar el enfoque en cada campo de entrada y evitar que los campos de entrada se enfoquen en el inicio de la actividad (haciendo que la vista de contenido sea el "receptor de enfoque"):

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final View view = findViewById(R.id.content); view.setFocusable(true); view.setFocusableInTouchMode(true); }


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

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 . Se cerrará con fuerza el teclado suave.


Una forma más Kotlin y de diseño de materiales utilizando TextInputEditText (este enfoque también es compatible con EditTextView ) ...

1. Haga que la vista principal (vista de contenido de su actividad / fragmento) se pueda hacer clic y enfocar agregando los siguientes atributos

android:focusable="true" android:focusableInTouchMode="true" android:clickable="true"

2.Cree una extensión para todas las Vistas (dentro de un archivo ViewExtension.kt, por ejemplo):

fun View.hideKeyboard(){ val inputMethodManager = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.hideSoftInputFromWindow(this.windowToken, 0) }

3.Cree un BaseTextInputEditText que herede de TextInputEditText. Implemente el método en FocusChanged para ocultar el teclado cuando la vista no está enfocada:

class BaseTextInputEditText(context: Context?, attrs: AttributeSet?) : TextInputEditText(context, attrs){ override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) { super.onFocusChanged(focused, direction, previouslyFocusedRect) if (!focused) this.hideKeyboard() } }

4. Simplemente llame a su nueva vista personalizada en su XML:

<android.support.design.widget.TextInputLayout android:id="@+id/textInputLayout" ...> <com.your_package.BaseTextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" ... /> </android.support.design.widget.TextInputLayout>

Eso es todo. No es necesario modificar sus controladores (fragmento o actividad) para manejar este caso repetitivo.


Utilice OnFocusChangeListener .

Por ejemplo:

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { hideKeyboard(); } } });

Actualización : también puede anular onTouchEvent() en su actividad y verificar las coordenadas del toque. Si las coordenadas están fuera de EditText, oculte el teclado.


es demasiado simple, simplemente haga que su diseño reciente se pueda hacer clic por medio de este código:

android:id="@+id/loginParentLayout" android:clickable="true" android:focusableInTouchMode="true"

y luego escriba un método y un OnClickListner para ese diseño, de modo que cuando se toque el diseño más alto donde se llame a un método en el que escribirá código para descartar el teclado. El siguiente es el código para ambos; // tienes que escribir esto en OnCreate ()

yourLayout.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { hideKeyboard(view); } });

método llamado de listner: -

public void hideKeyboard(View view) { InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(view.getWindowToken(), 0); }


Ruego: reconozco que no tengo influencia, pero por favor, tome mi respuesta en serio.

Problema: descarte el teclado virtual cuando haga clic fuera del teclado o edite el texto con un código mínimo.

Solución: Biblioteca externa conocida como Butterknife.

Una solución de línea:

@OnClick(R.id.activity_signup_layout) public void closeKeyboard() { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }

Solución más legible:

@OnClick(R.id.activity_signup_layout) public void closeKeyboard() { InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }

Explicación: vincule OnClick Listener con el ID principal del diseño XML de la actividad, de modo que cualquier clic en el diseño (no en el texto de edición o el teclado) ejecutará ese fragmento de código que ocultará el teclado.

Ejemplo: si su archivo de diseño es R.layout.my_layout y su ID de diseño es R.id.my_layout_id, entonces su llamada de vinculación de Butterknife debería tener el siguiente aspecto:

(@OnClick(R.id.my_layout_id) public void yourMethod { InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }

Enlace de documentación de Butterknife: http://jakewharton.github.io/butterknife/

Plug: Butterknife revolucionará tu desarrollo de Android. Considéralo.

Nota: Se puede lograr el mismo resultado sin el uso de la biblioteca externa Butterknife. Simplemente configure un OnClickListener en el diseño principal como se describe anteriormente.


Esta es una versión ligeramente modificada de la respuesta de fje que en su mayoría funcionó perfectamente.

Esta versión utiliza ACTION_DOWN, por lo que realizar una acción de desplazamiento también cierra el teclado. Tampoco se propaga el evento a menos que haga clic en otro EditText. Esto significa que hacer clic en cualquier lugar fuera de su EditText, incluso en otro clic, simplemente cierra el teclado.

@Override public boolean dispatchTouchEvent(MotionEvent ev) { if(ev.getAction() == MotionEvent.ACTION_DOWN) { final View view = getCurrentFocus(); if(view != null) { final View viewTmp = getCurrentFocus(); final View viewNew = viewTmp != null ? viewTmp : view; if(viewNew.equals(view)) { final Rect rect = new Rect(); final int[] coordinates = new int[2]; view.getLocationOnScreen(coordinates); rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight()); final int x = (int) ev.getX(); final int y = (int) ev.getY(); if(rect.contains(x, y)) { super.dispatchTouchEvent(ev); return true; } } else if(viewNew instanceof EditText || viewNew instanceof CustomEditText) { super.dispatchTouchEvent(ev); return true; } final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0); viewNew.clearFocus(); return true; } } return super.dispatchTouchEvent(ev); }


Esto puede ser viejo pero conseguí este trabajo al implementar una clase personalizada

public class DismissKeyboardListener implements OnClickListener { Activity mAct; public DismissKeyboardListener(Activity act) { this.mAct = act; } @Override public void onClick(View v) { if ( v instanceof ViewGroup ) { hideSoftKeyboard( this.mAct ); } } } public void hideSoftKeyboard(Activity activity) { InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0); }

La mejor práctica aquí es crear una clase de ayudante y cada contenedor Diseños relativos / lineales debe implementar esto

**** Tome nota de que solo el contenedor principal debe implementar esta clase (para optimización) ****

e implementarlo así:

Parent.setOnClickListener( new DismissKeyboardListener(this) );

la palabra clave esto es para la actividad. así que si estás en un fragmento, lo usas como getActivity ();

--- pulgares arriba si te ayuda ... --- saludos Ralph ---


Para resolver este problema, lo primero que debe hacer es usar setOnFocusChangeListener de ese Edittext

edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { Log.d("focus", "focus loosed"); // Do whatever you want here } else { Log.d("focus", "focused"); } } });

y luego lo que debe hacer es anular dispatchTouchEvent en la actividad que contiene ese Edittext, consulte el siguiente código

@Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { View v = getCurrentFocus(); if ( v instanceof EditText) { Rect outRect = new Rect(); v.getGlobalVisibleRect(outRect); if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) { Log.d("focus", "touchevent"); v.clearFocus(); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); } } } return super.dispatchTouchEvent(event); }

Ahora, lo que sucederá es cuando un usuario haga clic en el exterior y luego en primer lugar se llamará a dispatchTouchEvent, que luego eliminará el enfoque del editexto. Ahora se llamará a su OnFocusChangeListener. Se ha cambiado el enfoque.


Puede anular fácilmente el evento onKey () en la actividad y los fragmentos para ocultar el teclado.

@Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (keyCode == event.KEYCODE_ENTER) { intiateLoginProcess(); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getWindow().getCurrentFocus() .getWindowToken(), 0); return true; } } return false; }


Solo agrega este código en la clase @Overide

public boolean dispatchTouchEvent(MotionEvent ev) { View view = getCurrentFocus(); if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText && !view.getClass().getName().startsWith("android.webkit.")) { int scrcoords[] = new int[2]; view.getLocationOnScreen(scrcoords); float x = ev.getRawX() + view.getLeft() - scrcoords[0]; float y = ev.getRawY() + view.getTop() - scrcoords[1]; if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y > view.getBottom()) ((InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((this.getWindow().getDecorView().getApplicationWindowToken()), 0); } return super.dispatchTouchEvent(ev); }


Conseguí esto trabajando con una ligera variante en la solución de Fernando Camarago. En mi método onCreate adjunto un solo onTouchListener a la vista raíz, pero envío la vista en lugar de la actividad como un argumento.

findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { Utils.hideSoftKeyboard(v); return false; } });

En una clase separada de Utils es ...

public static void hideSoftKeyboard(View v) { InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(v.getWindowToken(), 0); }


Me parece que el bit de respuesta aceptada es complejo para este simple requisito. Esto es lo que funcionó para mí sin ningún problema.

findViewById(R.id.mainLayout).setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); return false; } });


Otra idea es anular el onInterceptTouchEventmétodo en la vista raíz de su Actividad.

El evento táctil pasa de la vista más frontal de la pantalla (donde ocurrió el evento táctil) a la pila de vistas que llaman al onTouchmétodo hasta que cualquiera de las vistas se vuelve verdadera, lo que indica que el evento táctil se consumió. Como muchas de las vistas consumen el evento táctil de forma predeterminada (es el caso de EditTexto TextView, por ejemplo), el evento no llega al onTouchmétodo de vista raíz de la Actividad .

Pero, antes de hacer este recorrido, el evento táctil recorre otra ruta, desde la vista raíz hacia abajo del árbol de la vista hasta que llega a la vista más frontal. Este recorrido se realiza llamando onInterceptTouchEvent. Si el método devuelve verdadero, intercepta el evento ... nahhh, pero eso es un pequeño truco, no creo que quieras hacer eso ni conocer los detalles. Lo que debe saber es que puede anular este método en la vista raíz de su Actividad y colocar allí el código para ocultar el teclado cuando sea necesario.


@Override public boolean onTouchEvent(MotionEvent event) { InputMethodManager imm = (InputMethodManager)getSystemService(Context. INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); return true; }