¿Cómo eliminar el enfoque sin establecer el enfoque en otro control?


95

Me gusta que mis UI sean intuitivas; cada pantalla debe guiar al usuario de forma natural y discreta hacia el siguiente paso de la aplicación. Salvo eso, me esfuerzo por hacer las cosas lo más confusas y confusas posible.

Es una broma :-)

Tengo tres TableRows, cada uno contiene un control EditText de solo lectura y no enfocable y luego un botón a su derecha. Cada botón inicia la misma actividad pero con un argumento diferente. El usuario realiza una selección allí y finaliza la subactividad, llenando el correspondiente EditTextcon la selección del usuario.

Es el mecanismo clásico de valores en cascada; cada selección reduce las opciones disponibles para la siguiente selección, etc. Por lo tanto, estoy deshabilitando ambos controles en cada una de las siguientes filas hasta que EditText en la fila actual contenga un valor.

Necesito hacer una de dos cosas, en este orden de preferencia:

  1. Cuando se hace clic en un botón, elimine inmediatamente el enfoque sin establecer el enfoque en un botón diferente
  2. Establezca el foco en el primer botón cuando comience la actividad

El problema se manifiesta después de que regresa la subactividad; el botón en el que se hizo clic conserva el enfoque.

Re: # 1 arriba - No parece haber un removeFocus()método, o algo similar

Re: # 2 anterior: puedo usar requestFocus()para establecer el enfoque en el botón en la siguiente fila, y eso funciona después de que regresa la subactividad, pero por alguna razón no funciona en la actividad principal onCreate().

Necesito coherencia en la interfaz de usuario en cualquier dirección: o ningún botón tiene el foco después de que finaliza la subactividad o cada botón recibe el foco según su lugar en el flujo lógico, incluido el primer (y único) botón activo antes de cualquier selección.

Respuestas:


173

El uso de clearFocus () tampoco parecía funcionar para mí como lo encontró (vio en los comentarios a otra respuesta), pero lo que funcionó para mí al final fue agregar:

<LinearLayout 
    android:id="@+id/my_layout" 
    android:focusable="true" 
    android:focusableInTouchMode="true" ...>

a mi vista de diseño de nivel superior (un diseño lineal). Para quitar el foco de todos los botones / EditTexts, etc., puede simplemente hacer

LinearLayout myLayout = (LinearLayout) activity.findViewById(R.id.my_layout);
myLayout.requestFocus();

Solicitar enfoque no hizo nada a menos que establezca la vista para que sea enfocable.


Por un momento pensé que esto podría funcionar. "¡Qué hermoso en su sencillez!" Me dije a mi mismo. Por desgracia, no fue así. Incluso cuando elimino requestFocus (), el botón de la siguiente fila se enfoca. Esto estaría bien como una segunda preferencia, pero solo si de alguna manera puedo establecer el enfoque en el primer botón en onCreate ().
InteXX

@InteXX: Me encontré con este problema nuevamente hoy y encontré una solución. Sé que ahora has tomado una ruta diferente, pero pruébalo si alguna vez te encuentras en el mismo barco nuevamente.
actionshrimp

"Sé que has tomado una ruta diferente ahora" Todavía no es demasiado tarde para retroceder :-) Lo intentaré y te lo haré saber, gracias.
InteXX

Maldito. Casi, pero no del todo. Sí, quita el enfoque del último botón en el que se hizo clic, pero también evita que CUALQUIER botón se enfoque. Esto significaría que mis usuarios no táctiles no podrían hacer clic en un botón. ¿Está haciendo lo mismo por ti?
InteXX

6
Esto no funcionará en ScrollView. Si su vista superior es ScrollView, use esto en su hijo.
Uroš Podkrižnik

79

Antigua pregunta, pero me la encontré cuando tuve un problema similar y pensé en compartir lo que terminé haciendo.

La vista que ganó atención fue diferente cada vez, así que usé la muy genérica:

View current = getCurrentFocus();
if (current != null) current.clearFocus();

12
Manera elegante de hacer esto. Es posible que desee verificar si hay un valor nulo de getCurrentFocus () antes de llamar a clearFocus ()
Vering

4
+1 ¡Sí, tendrás que lanzar ese cheque nulo! - ¿Por qué Java no puede simplemente implementar un operador de recorrido seguro? Sería tan simple como getCurrentFocus()?.clearFocus();, tan agradable y elegante: - /
Levita

1
@willlma: Sí, esto fue exactamente lo que quise decir.
Ver el

5
@Levit Muy rápido. :-) Pero incluso si Java implementara un operador de este tipo, Android todavía tardaría 4 años en ponerse al día.
Greg Brown

2
@Levit, probablemente ya lo hayas encontrado, pero Kotlin.
prodaea

9
  1. Puede utilizar View.clearFocus().

  2. Utilice View.requestFocus()llamado desde onResume().


@siliconeagle: Esto es MUY MUY extraño. (Gracias por el puntero para clearFocus () por cierto, no estaba al tanto de esto.) Cuando hago clic en el primer botón, hago una selección y luego regreso, el primer botón ya no puede recibir el enfoque. No estoy configurando enfocable para este botón en ninguna parte de mi código. Me gustaría mostrarle mi código, pero no hay suficientes caracteres disponibles en esta ventana de edición y, como soy nuevo en, no estoy seguro de si debería ingresar otra respuesta solo para poder publicar el código.
InteXX

@siliconeagle: Desafortunadamente, clearFocus () no funciona: los botones mantienen el foco cuando regresa la subactividad.
InteXX

@siliconeagle: OK, no importa ese primer comentario. Estaba usando setFocusable (false) en el evento de clic del botón y olvidé volver a encenderlo después de que regresara la subactividad. clearFocus () todavía no tiene ningún efecto, sin embargo, me pregunto por qué. Lo llamo en todos los botones de onActivityResult (), pero el botón en el que se hizo clic aún conserva el foco. Impar.
InteXX

@siliconeagle: @actionshrimp: He decidido eliminar todos los comandos y configuraciones relacionados con el enfoque. Mi intención original era evitar centrarme en los botones deshabilitados, pero si esto es lo que cuesta, no vale la pena. Sin requestFocus (), clearFocus () o setFocusable (), ningún botón retiene el enfoque después de que regresa la subactividad. Es el menor de dos gorgojos; supongo que tendré que vivir con que el usuario pueda establecer el enfoque en un botón desactivado.
InteXX

los elementos deshabilitados no se pueden enfocar AFAIK ... use setEnabled (false)
siliconeagle

8

android:descendantFocusability="beforeDescendants"

el uso de lo siguiente en la actividad con algunas opciones de diseño a continuación pareció funcionar como se desea.

 getWindow().getDecorView().findViewById(android.R.id.content).clearFocus();

en relación con los siguientes parámetros en la vista raíz.

<?xml
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:descendantFocusability="beforeDescendants" />

https://developer.android.com/reference/android/view/ViewGroup#attr_android:descendantFocusability

Respuesta gracias a: https://forums.xamarin.com/discussion/1856/how-to-disable-auto-focus-on-edit-text

Acerca de windowSoftInputMode

Hay otro punto de discordia que hay que tener en cuenta. De forma predeterminada, Android asignará automáticamente el enfoque inicial al primer EditText o control enfocable en su Actividad. Naturalmente, se deduce que el InputMethod (normalmente el teclado virtual) responderá al evento de enfoque mostrándose. 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"/>

gran referencia


6
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:id="@+id/ll_root_view"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical">

LinearLayout llRootView = findViewBindId(R.id.ll_root_view);
llRootView.clearFocus();

Lo uso cuando ya terminé de actualizar la información del perfil y elimino todo el foco de EditText en mi diseño

====> Actualización: En el contenido del diseño principal, mi EditText agrega la línea:

android:focusableInTouchMode="true"


2

En primer lugar, funcionará al 100% ........

  1. Crear onResume()método.
  2. Dentro de este onResume()encuentra la vista que se está enfocando una y otra vez por findViewById().
  3. Dentro de este onResume()conjunto requestFocus()a esta vista.
  4. Dentro de este onResume()conjunto clearFocusa esta vista.
  5. Vaya en xml del mismo diseño y encuentre la vista superior en la que desea enfocar y establecer focusableverdadera y focusableInTuchverdadera.
  6. Dentro de esto, onResume()encuentre la vista superior de arriba porfindViewById
  7. Dentro de este onResume()conjunto requestFocus()a esta vista al final.
  8. Y ahora disfruta ...

2

Intenté deshabilitar y habilitar la capacidad de enfoque para la vista y funcionó para mí (el enfoque se restableció):

focusedView.setFocusable(false);
focusedView.setFocusableInTouchMode(false);
focusedView.setFocusable(true);
focusedView.setFocusableInTouchMode(true);

1

Puede intentar desactivar la capacidad de la actividad principal para guardar su estado (haciendo que olvide qué control tenía texto y qué tenía foco). Necesitará tener alguna otra forma de recordar lo que tienen sus EditText y repoblarlos enResume (). Inicie sus subactividades con startActivityForResult () y cree un controlador onActivityResult () en su actividad principal que actualizará el EditText correctamente. De esta manera, puede establecer el botón adecuado que desea enfocado enResume () al mismo tiempo que repobla el EditText usando un myButton.post (new Runnable () {run () {myButton.requestFocus ();}});

El método View.post () es útil para establecer el enfoque inicialmente porque ese ejecutable se ejecutará después de que se cree la ventana y las cosas se calmen, permitiendo que el mecanismo de enfoque funcione correctamente en ese momento. Intentar establecer el enfoque durante onCreate / Start / Resume () generalmente tiene problemas, he encontrado.

Tenga en cuenta que este es un pseudocódigo y no se ha probado, pero es una posible dirección que podría intentar.


Pensándolo bien ... intente usar las cosas View.post () primero en lugar de desactivar el estado guardado de la Actividad. Eso podría hacer el truco por sí solo.
Tío Code Monkey

Por desgracia, ya no tengo una manera fácil de probar esto por nosotros. Desde entonces, decidí abandonar el modelo de código nativo e ir con HTML5 / CSS3 para aplicaciones móviles y, por lo tanto, he rediseñado mi sistema en consecuencia. Pero gracias por lo que parece ser una respuesta muy detallada. Lo voté a favor.
InteXX

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

Agréguelos a su ViewGroup que incluye su EditTextView. Funciona correctamente para mi diseño de restricción. Espero que esto ayude


0

Pruebe lo siguiente (llamando clearAllEditTextFocuses();)

private final boolean clearAllEditTextFocuses() {
    View v = getCurrentFocus();
    if(v instanceof EditText) {
        final FocusedEditTextItems list = new FocusedEditTextItems();
        list.addAndClearFocus((EditText) v);

        //Focus von allen EditTexten entfernen
        boolean repeat = true;
        do {
            v = getCurrentFocus();
            if(v instanceof EditText) {
                if(list.containsView(v))
                    repeat = false;
                else list.addAndClearFocus((EditText) v);
            } else repeat = false;
        } while(repeat);

        final boolean result = !(v instanceof EditText);
        //Focus wieder setzen
        list.reset();
        return result;
    } else return false;
}

private final static class FocusedEditTextItem {

    private final boolean focusable;

    private final boolean focusableInTouchMode;

    @NonNull
    private final EditText editText;

    private FocusedEditTextItem(final @NonNull EditText v) {
        editText = v;
        focusable = v.isFocusable();
        focusableInTouchMode = v.isFocusableInTouchMode();
    }

    private final void clearFocus() {
        if(focusable)
            editText.setFocusable(false);
        if(focusableInTouchMode)
            editText.setFocusableInTouchMode(false);
        editText.clearFocus();
    }

    private final void reset() {
        if(focusable)
            editText.setFocusable(true);
        if(focusableInTouchMode)
            editText.setFocusableInTouchMode(true);
    }

}

private final static class FocusedEditTextItems extends ArrayList<FocusedEditTextItem> {

    private final void addAndClearFocus(final @NonNull EditText v) {
        final FocusedEditTextItem item = new FocusedEditTextItem(v);
        add(item);
        item.clearFocus();
    }

    private final boolean containsView(final @NonNull View v) {
        boolean result = false;
        for(FocusedEditTextItem item: this) {
            if(item.editText == v) {
                result = true;
                break;
            }
        }
        return result;
    }

    private final void reset() {
        for(FocusedEditTextItem item: this)
            item.reset();
    }

}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.