android - quitar - quit focus edittext
EditText, claro foco en el tacto afuera (13)
Basándose en la respuesta de Ken, esta es la solución más modular de copiar y pegar.
No se necesita XML.
Colóquelo en su Actividad y se aplicará a todos los EditTexts, incluidos aquellos dentro de los fragmentos dentro de esa actividad.
@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())) {
v.clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent( event );
}
Mi diseño contiene ListView
, SurfaceView
y EditText
. Cuando hago clic en EditText
, recibe el foco y aparece el teclado en pantalla. Cuando hago clic en algún lugar fuera de EditText
, todavía tiene el foco (no debería). Creo que podría configurar OnTouchListener
en las otras vistas en el diseño y borrar manualmente el EditText
de EditText
. Pero parece demasiado hackish ...
También tengo la misma situación en el otro diseño: vista de lista con diferentes tipos de elementos, algunos de los cuales tienen dentro EditText
. Actúan justo como escribí arriba.
La tarea es hacer que EditText
pierda el foco cuando el usuario toca algo fuera de él.
He visto preguntas similares aquí, pero no he encontrado ninguna solución ...
Como @pcans sugirió que puede hacer esto reemplazando dispatchTouchEvent(MotionEvent event)
en su actividad.
Aquí obtenemos las coordenadas táctiles y las comparamos para ver los límites. Si el toque se realiza fuera de una vista, entonces haz algo.
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View yourView = (View) findViewById(R.id.view_id);
if (yourView != null && yourView.getVisibility() == View.VISIBLE) {
// touch coordinates
int touchX = (int) event.getX();
int touchY = (int) event.getY();
// get your view coordinates
final int[] viewLocation = new int[2];
yourView.getLocationOnScreen(viewLocation);
// The left coordinate of the view
int viewX1 = viewLocation[0];
// The right coordinate of the view
int viewX2 = viewLocation[0] + yourView.getWidth();
// The top coordinate of the view
int viewY1 = viewLocation[1];
// The bottom coordinate of the view
int viewY2 = viewLocation[1] + yourView.getHeight();
if (!((touchX >= viewX1 && touchX <= viewX2) && (touchY >= viewY1 && touchY <= viewY2))) {
Do what you want...
// If you don''t want allow touch outside (for example, only hide keyboard or dismiss popup)
return false;
}
}
}
return super.dispatchTouchEvent(event);
}
Además, no es necesario verificar la visibilidad y visibilidad de la vista si el diseño de su actividad no cambia durante el tiempo de ejecución (por ejemplo, no agrega fragmentos ni reemplaza / elimina vistas del diseño). Pero si desea cerrar (o hacer algo similar) el menú contextual personalizado (como en Google Play Store cuando usa el menú de desbordamiento del elemento), es necesario verificar la existencia de la vista. De lo contrario, obtendrás una NullPointerException
.
Intenté todas estas soluciones. El de edc598 fue el más cercano al trabajo, pero los eventos táctiles no se activaron en otras View
encuentran en el diseño. En caso de que alguien necesite este comportamiento, esto es lo que terminé haciendo:
FrameLayout
FrameLayout (invisible) llamado touchInterceptor como la última View
en el diseño para que se superponga todo ( edit: también tienes que usar un RelativeLayout
como el diseño principal y otorgar los atributos touchInterceptor fill_parent
). Luego lo usé para interceptar toques y determinar si el toque estaba sobre EditText
o no:
FrameLayout touchInterceptor = (FrameLayout)findViewById(R.id.touchInterceptor);
touchInterceptor.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mEditText.isFocused()) {
Rect outRect = new Rect();
mEditText.getGlobalVisibleRect(outRect);
if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
mEditText.clearFocus();
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return false;
}
});
Devuelve falso para permitir que la manipulación táctil se caiga.
Es hacky, pero es lo único que funcionó para mí.
La mejor forma es usar el método predeterminado clearFocus()
¿Sabes cómo resolver códigos en el onTouchListener
verdad?
Simplemente llame a EditText.clearFocus()
. last EditText
foco en el last EditText
.
La respuesta de Ken funciona, pero es hacky. Como pcans alude en el comentario de la respuesta, lo mismo podría hacerse con dispatchTouchEvent. Esta solución es más limpia ya que evita tener que hackear el XML con FrameLayout ficticio transparente. Esto es lo que parece:
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
EditText mEditText = findViewById(R.id.mEditText);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (mEditText.isFocused()) {
Rect outRect = new Rect();
mEditText.getGlobalVisibleRect(outRect);
if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
mEditText.clearFocus();
//
// Hide keyboard
//
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent(event);
}
Para la vista principal de EditText, permita que los siguientes 3 atributos sean " verdaderos ":
hacer clic , enfocable , enfocableInTouchMode .
Si una vista desea recibir el foco, debe cumplir estas 3 condiciones.
Ver android.view :
public boolean onTouchEvent(MotionEvent event) {
...
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
...
if (isFocusable() && isFocusableInTouchMode()
&& !isFocused()) {
focusTaken = requestFocus();
}
...
}
...
}
Espero eso ayude.
Para mí, debajo de las cosas trabajadas:
1. Agregando android:clickable="true"
y android:focusableInTouchMode="true"
al parentLayout
de EditText
es decir android.support.design.widget.TextInputLayout
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusableInTouchMode="true">
<EditText
android:id="@+id/employeeID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number"
android:hint="Employee ID"
tools:layout_editor_absoluteX="-62dp"
tools:layout_editor_absoluteY="16dp"
android:layout_marginTop="42dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="36dp"
android:layout_marginEnd="36dp" />
</android.support.design.widget.TextInputLayout>
2. Reemplazando dispatchTouchEvent
en la clase Activity e insertando la función hideKeyboard()
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View view = getCurrentFocus();
if (view != null && view instanceof EditText) {
Rect r = new Rect();
view.getGlobalVisibleRect(r);
int rawX = (int)ev.getRawX();
int rawY = (int)ev.getRawY();
if (!r.contains(rawX, rawY)) {
view.clearFocus();
}
}
}
return super.dispatchTouchEvent(ev);
}
public void hideKeyboard(View view) {
InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
3. Agregando setOnFocusChangeListener
para EditText
EmployeeId.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
hideKeyboard(v);
}
}
});
Para perder el foco cuando se toca otra vista, ambas vistas deben configurarse como view.focusableInTouchMode (true).
Pero parece que los enfoques de uso en modo táctil no son recomendables. Por favor, eche un vistazo aquí: http://android-developers.blogspot.com/2008/12/touch-mode.html
Probablemente ya hayas encontrado la respuesta a este problema, pero he estado buscando cómo resolverlo y todavía no puedo encontrar exactamente lo que estaba buscando, así que pensé en publicarlo aquí.
Lo que hice fue lo siguiente (esto es muy generalizado, el propósito es darte una idea de cómo proceder, copiar y pegar todo el código no funcionará O: D):
Primero tiene el EditText y cualquier otra vista que desee en su programa envuelto por una sola vista. En mi caso, utilicé LinearLayout para envolver todo.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mainLinearLayout">
<EditText
android:id="@+id/editText"/>
<ImageView
android:id="@+id/imageView"/>
<TextView
android:id="@+id/textView"/>
</LinearLayout>
Luego, en su código, debe configurar un Listener Touch en su LinearLayout principal.
final EditText searchEditText = (EditText) findViewById(R.id.editText);
mainLinearLayout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(searchEditText.isFocused()){
if(event.getY() >= 72){
//Will only enter this if the EditText already has focus
//And if a touch event happens outside of the EditText
//Which in my case is at the top of my layout
//and 72 pixels long
searchEditText.clearFocus();
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
Toast.makeText(getBaseContext(), "Clicked", Toast.LENGTH_SHORT).show();
return false;
}
});
Espero que esto ayude a algunas personas. O al menos les ayuda a comenzar a resolver su problema.
Realmente creo que es una forma más sólida de usar getLocationOnScreen
que getGlobalVisibleRect
. Porque encuentro un problema. Hay una vista de lista que contiene algún texto de edición y establece ajustpan
en la actividad. Encuentro que getGlobalVisibleRect
devuelve un valor que parece incluir el desplazamiento Y en él, pero event.getRawY siempre está en la pantalla. El siguiente código funciona bien.
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if ( v instanceof EditText) {
if (!isPointInsideView(event.getRawX(), event.getRawY(), v)) {
Log.i(TAG, "!isPointInsideView");
Log.i(TAG, "dispatchTouchEvent clearFocus");
v.clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent( event );
}
/**
* Determines if given points are inside view
* @param x - x coordinate of point
* @param y - y coordinate of point
* @param view - view object to compare
* @return true if the points are within view bounds, false otherwise
*/
private boolean isPointInsideView(float x, float y, View view) {
int location[] = new int[2];
view.getLocationOnScreen(location);
int viewX = location[0];
int viewY = location[1];
Log.i(TAG, "location x: " + location[0] + ", y: " + location[1]);
Log.i(TAG, "location xWidth: " + (viewX + view.getWidth()) + ", yHeight: " + (viewY + view.getHeight()));
// point is inside view bounds
return ((x > viewX && x < (viewX + view.getWidth())) &&
(y > viewY && y < (viewY + view.getHeight())));
}
Simplemente defina dos propiedades de parent de ese EditText
como:
android:clickable="true"
android:focusableInTouchMode="true"
Por lo tanto, cuando el usuario toque fuera del área EditText
, el enfoque se eliminará porque el enfoque se transferirá a la vista principal.
Simplemente ponga estas propiedades en la parte superior del padre.
android:focusableInTouchMode="true"
android:clickable="true"
android:focusable="true"
Tengo un ListView
compuesto por vistas de EditText
. El escenario dice que después de editar el texto en una o más filas, debemos hacer clic en un botón llamado "finalizar". onFocusChanged
en la vista EditText
dentro de listView
pero después de hacer clic en finish no se guardan los datos. El problema fue resuelto agregando
listView.clearFocus();
dentro de onClickListener
para el botón "finalizar" y los datos se guardaron con éxito.