¿Cómo ocultar el teclado suave en Android después de hacer clic fuera de EditText?

Ok, todos saben que para ocultar un teclado debes implementarlo:

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

Pero el gran 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.

Traté de usar el 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 y enfocar oyente sin ningún éxito.

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

¿Hay una forma estándar de hacer esto? en iPhone fue realmente fácil.

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 difícil es cuándo llamarlo. Puedes escribir un método que itere a través de cada View en tu actividad, y verificar si es una instanceof EditText si no registra un setOnTouchListener para ese componente y todo estará en su lugar. En caso de que se pregunte cómo hacerlo, de hecho es bastante simple. Esto es lo que haces, escribes un método recursivo como el siguiente, de hecho, puedes usarlo 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 setContentView en su actividad. En caso de que se pregunte qué parámetro aprobaría, es la id del contenedor padre. Asigna una id a tu contenedor padre como

...

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

Si desea utilizar 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 amplíen esta actividad y llamen a su setupUI() en el método onCreate() .

Espero eso ayude.

Si usa más de 1 actividad, defina el diseño común de ID a principal como ...

Luego, amplíe una clase desde Activity y defina setupUI(findViewById(R.id.main_parent)) dentro de OnResume() y amplíe esta clase en lugar de `` Activity in your program

Puede lograrlo siguiendo estos pasos:

  1. Haga que la vista principal (vista de contenido de su actividad) pueda hacer clic y enfocarse 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 texto de edición.

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

Como se señala en uno de los comentarios a continuación, es posible que esto no funcione si la vista principal es un ScrollView. En tal caso, el ModoEnlaTouch seleccionable y enfocable se puede agregar a la vista directamente debajo de la Vista de desplazamiento.

Encuentro que la respuesta aceptada es 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 pon el siguiente código en el método onTouch.

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

De esta forma, no tiene que iterar sobre todas las vistas.

Obtuve una solución más para ocultar el teclado de la siguiente manera:

 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 virtual.

Bueno, logré resolver el problema de alguna manera, 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 en el método getFields (). Esta matriz se inicializa en los métodos onStart () tales como:

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


No es perfecto, el tiempo del evento de arrastre solo se basa en la heurística, 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 se mostraría al hacer clic en otro EditText.

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

Use 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.

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 probé, ¡funciona perfecto!

Anular public boolean dispatchTouchEvent (evento MotionEvent) en cualquier actividad (o extender 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, pero creo que el enfoque que se indica a continuación podría tener un beneficio adicional con respecto a la eficiencia y la elegancia.

Necesito este comportamiento para todas mis actividades, así que creé una clase CustomActivity que hereda de la clase Activity y “enganché” la función dispatchTouchEvent . Hay principalmente dos condiciones para cuidar:

  1. Si el foco no cambia y alguien está tocando fuera del campo de entrada actual, entonces descarte el IME
  2. Si el foco ha cambiado y el siguiente elemento enfocado no es una instancia de ningún tipo de campo de entrada, entonces 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, lo que permite borrar el foco en cada campo de entrada y evitar que los campos de entrada se centren en el inicio de actividad (haciendo que el contenido vea el “receptor de foco”):

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

Modifiqué la solución de Andre Luis IM. Logré 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. Como el evento burbujea hasta que se consume (EditText es una de las vistas que lo consume de manera 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; } }); 

Me gustó el enfoque de llamar a dispatchTouchEvent realizado 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 (podría haber bastantes 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 cambiaste entre dos componentes de entrada.

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

Aquí hay otra variación de la respuesta de fje que aborda los problemas planteados 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 descendente, tomamos nota de la vista enfocada actualmente (si corresponde) y si el toque estaba dentro de ella, guardando ambos bits de información para más adelante.

En la acción ascendente, primero enviamos, para permitir que otra vista tome el foco. Si después de eso, la vista enfocada actualmente es la vista enfocada originalmente, y el toque descendente 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 EditText , 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 actualmente enfocado, 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 actualmente enfocado que no es otro EditText , el teclado se cierra
  • cuando presiona EditText un EditText para que aparezca la barra de acción contextual (con los botones cortar / copiar / pegar), el teclado permanece abierto, aunque la acción UP se realizó fuera del EditText enfocado (que se movió hacia abajo para dejar espacio para el TAXI). Sin embargo, tenga en cuenta que cuando toca un botón en el CAB, cerrará el teclado. Eso puede o no ser deseable; si quieres cortar / copiar de un campo y pegarlo a otro, sería. Si desea volver a pegar en el mismo EditText , no sería así.
  • cuando EditText enfocado está en la parte inferior de la pantalla y hace clic largo en algún texto para seleccionarlo, EditText mantiene el foco y, por lo tanto, el teclado se abre como desee, porque hacemos la comprobación “toque está dentro de límites de vista” en el 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); } 

es muy simple, solo haga que su diseño reciente pueda hacer clic y sea enfocable mediante 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 toca el diseño superior, llame a un método en el que escriba el código para descartar el teclado. 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 desde listner: –

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

Plea: reconozco que no tengo influencia, pero por favor toma mi respuesta en serio.

Problema: Descarte el teclado suave al hacer clic fuera del teclado o edite texto con un código mínimo.

Solución: Biblioteca externa conocida como Butterknife.

Solución de una 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: Enlace OnClick Listener a la identificación principal de Layout XML de la actividad, para que cualquier clic en el diseño (no en el texto de edición o el teclado) ejecute 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 a Butterknife debe verse así:

 (@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: El mismo resultado se puede lograr sin el uso de la biblioteca externa Butterknife. Simplemente configure OnClickListener en el diseño principal como se describe arriba.

Hay un enfoque más simple, basado en el mismo problema de iPhone. Simplemente anule el diseño del fondo en el evento táctil, donde está contenido el texto de edición. Solo use este código en OnCreate de la actividad (login_fondo es el diseño 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 refinado el método, coloque el siguiente código en alguna clase de utilidad de UI (preferiblemente, no necesariamente) para que se pueda acceder 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 debe 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 de la raíz del grupo actual (no debe haber configurado el id en la vista raíz).

Saludos 🙂

Intenta poner stateHidden como tu actividad windowSoftInputMode value

http://developer.android.com/reference/android/R.attr.html#windowSoftInputMode

Por ejemplo para tu actividad:

 this.getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); 

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); } 

Una forma más de Kotlin & Material Design usando TextInputEditText (este enfoque también es compatible con EditTextView ) …

1. Haga que la vista principal (vista de contenido de su actividad / fragmento) pueda hacer clic y enfocarse 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.Crear un BaseTextInputEditText que herede TextInputEditText. Implemente el método en FocoCambiado 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:

    

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

Encuentro que la respuesta aceptada es un poco compleja 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; } }); 

Esto puede ser antiguo pero lo hice funcionar implementando 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); } 

the best practice here is to create a Helper class and every container Relative / Linear Layouts should implement this.

**** Take note only the main Container should implement this class (For optimization) ****

and implement it like this :

 Parent.setOnClickListener( new DismissKeyboardListener(this) ); 

the keyword this is for Activity. so if you are on fragment you use like getActivity();

—thumbs up if it help you… — cheers Ralph —

This is a slightly modified version of fje’s answer which mostly worked perfectly.

This version uses ACTION_DOWN so performing a scroll action also closes the keyboard. It also doesn’t propagate the event unless you click on another EditText. This means that clicking anywhere outside your EditText, even on another clickable, simply closes the keyboard.

 @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); } 

Lo 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); } 

Hide keyboard code :

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

Hecho

To solve this problem what you have to do is first use setOnFocusChangeListener of that 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"); } } }); 

and then what you need to do is override dispatchTouchEvent in the activity which contains that Edittext see below code

 @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); } 

Now what will happen is when a user click outside then firstly this dispatchTouchEvent will get called which then will clear focus from the editext now your OnFocusChangeListener will get called that focus has been changed now here you can do anything which you wanted to do hope it works

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

Other idea is to override onInterceptTouchEvent method on the root view for your Activity.

The touch event goes from the front most view on the screen (where the touch event occurred) down the stack of views calling the onTouch method until any of the views return true, indicating that the touch event was consumed. As many of the view consumes the touch event by default (that is the case of EditText or TextView , for instance), the event does not get to the Activity’s root View onTouch method.

But, before do this traversal, the touch event travels another path, going from the root view down the view tree until it gets to the front most view. This traversal is done by calling onInterceptTouchEvent . If the method returns true, it intercepts the event… nahhh, but that is a little bit trick, I don’t think you want to do that nor to know the details. What you need to know is that you can override this method on the root view for your Activity, and put there the code to hide the keyboard when necessary.

I got this working with a slight variant on Fernando Camarago’s solution. In my onCreate method I attach a single onTouchListener to the root view but send the view rather than activity as an argument.

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

In a separate Utils class is…

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

You may easily override the onKey() event in activity and fragments to hide the keyboard.

 @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; } 

hey guys i have simple solution for this problem and this solution can be used for simple registration or login form. my solution is same as i implemented in ios setontouch listener to Main view

activity_main.xml add ID to your main relative layout android:id="@+id/mainlayout"

and add this code to your activity

  RelativeLayout mainLayout = (RelativeLayout)findViewById(R.id.mainlayout); mainLayout.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub Log.d("Json Response", "Touch outside"); InputMethodManager inputMethodManager = (InputMethodManager) MainActivity.this.getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(MainActivity.this.getCurrentFocus().getWindowToken(), 0); return false; } });