Come rimuovere lo stato attivo senza impostare lo stato attivo su un altro controllo?


95

Mi piace che le mie interfacce utente siano intuitive; ogni schermata dovrebbe guidare l'utente in modo naturale e discreto al passaggio successivo nell'app. A parte ciò, mi sforzo di rendere le cose il più confuse e confuse possibile.

Stavo solo scherzando :-)

Ne ho tre TableRow, ciascuno contenente un controllo EditText di sola lettura e non attivabile e quindi un pulsante alla sua destra. Ogni pulsante avvia la stessa attività ma con un argomento diverso. L'utente effettua una selezione lì e l'attività secondaria termina, compilando l'appropriato EditTextcon la selezione dell'utente.

È il classico meccanismo di valori a cascata; ogni selezione restringe le opzioni disponibili per la selezione successiva, ecc. Pertanto, disabilito entrambi i controlli su ciascuna delle righe successive finché EditText sulla riga corrente non contiene un valore.

Devo fare una delle due cose, in questo ordine di preferenza:

  1. Quando si fa clic su un pulsante, rimuovere immediatamente lo stato attivo senza impostare lo stato attivo su un pulsante diverso
  2. Imposta lo stato attivo sul primo pulsante quando inizia l'attività

Il problema si manifesta dopo il ritorno della sottoattività; il pulsante su cui si è fatto clic mantiene lo stato attivo.

Ri: # 1 sopra - Non sembra esserci un removeFocus()metodo o qualcosa di simile

Ri: # 2 sopra - Posso usare requestFocus()per mettere a fuoco il pulsante nella riga successiva, e funziona dopo il ritorno dell'attività secondaria, ma per qualche motivo non funziona nell'attività genitore onCreate().

Ho bisogno di coerenza dell'interfaccia utente in entrambe le direzioni: o nessun pulsante è attivo al termine dell'attività secondaria o ogni pulsante viene attivato a seconda della sua posizione nel flusso logico, incluso il primo (e unico) pulsante attivo prima di qualsiasi selezione.

Risposte:


173

L'uso di clearFocus () non sembra funzionare nemmeno per me come hai trovato (visto nei commenti a un'altra risposta), ma ciò che ha funzionato per me alla fine è stato l'aggiunta:

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

al mio livello più alto Layout View (un layout lineare). Per rimuovere lo stato attivo da tutti i pulsanti / EditTexts ecc., Puoi semplicemente farlo

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

La richiesta di messa a fuoco non ha fatto nulla a meno che non avessi impostato la vista per essere focalizzabile.


Per un fugace momento ho pensato che potesse funzionare. "Com'è bello nella sua semplicità!" Mi sono detto. Ahimè, non doveva essere. Anche quando rimuovo requestFocus () il pulsante della riga successiva diventa attivo. Questa sarebbe una seconda preferenza, ma solo se in qualche modo posso impostare lo stato attivo sul primo pulsante in onCreate ().
InteXX

@InteXX: mi sono imbattuto di nuovo in questo problema oggi e ho trovato una soluzione. So che hai intrapreso una strada diversa ora, ma fai un tentativo se ti ritrovi di nuovo nella stessa barca!
actionshrimp

"So che hai seguito una strada diversa ora" Non è ancora troppo tardi per tornare indietro :-) Proverò e ti farò sapere, grazie.
InteXX

Darn. Quasi, ma non del tutto. Sì, toglie il fuoco all'ultimo pulsante cliccato, ma impedisce anche a QUALSIASI pulsante di ottenere lo stato attivo. Ciò significherebbe che i miei utenti non touch non sarebbero in grado di fare clic su un pulsante. Sta facendo lo stesso per te?
InteXX

6
Questo non funzionerà su ScrollView. Se la tua vista dall'alto è ScrollView, usala sul suo bambino.
Uroš Podkrižnik

79

Vecchia domanda, ma mi sono imbattuto quando ho avuto un problema simile e ho pensato di condividere quello che ho finito per fare.

La vista che ha ottenuto l'attenzione era diversa ogni volta, quindi ho usato il molto generico:

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

12
Modo elegante per farlo. Si potrebbe voler verificare la presenza di null un valore da getCurrentFocus () prima di chiamare clearFocus ()
Vering

4
+1 Sì, dovrai inserire quell'assegno nullo! - Perché Java non può semplicemente implementare un operatore di attraversamento sicuro? Sarebbe tanto semplice quanto getCurrentFocus()?.clearFocus();, così carino ed elegante: - /
Levita

1
@ Willlma: Sì, era esattamente quello che intendevo.
Vering

5
@ Levit Very Swift-like. :-) Ma anche se Java implementasse un simile operatore, Android impiegherebbe comunque 4 anni per recuperare.
Greg Brown

2
@ Levit, probabilmente l'hai già trovato, ma Kotlin.
prodaea

9
  1. Puoi usare View.clearFocus().

  2. Usa View.requestFocus()chiamato da onResume().


@siliconeagle: Ora questo è molto MOLTO strano. (Grazie per il puntatore a clearFocus () btw - non ne ero a conoscenza.) Quando faccio clic sul primo pulsante, effettuo una selezione e poi ritorno, il primo pulsante non può più ricevere lo stato attivo. Non sto impostando l'attivazione per questo pulsante da nessuna parte nel mio codice. Vorrei mostrarti il ​​mio codice, ma non ci sono abbastanza caratteri disponibili in questa finestra di modifica ed essendo nuovo in SO non sono sicuro se devo inserire un'altra risposta solo per poter inserire il codice.
InteXX

@siliconeagle: Sfortunatamente, clearFocus () non funziona: i pulsanti mantengono il focus quando torna l'attività secondaria.
InteXX

@siliconeagle: OK, non importa quel primo commento. Stavo usando setFocusable (false) nell'evento click del pulsante e dimenticavo di riattivarlo dopo il ritorno dell'attività secondaria. clearFocus () non ha ancora alcun effetto - mi chiedo perché? Lo chiamo su tutti i pulsanti da onActivityResult (), ma il pulsante cliccato mantiene lo stato attivo. Dispari.
InteXX

@siliconeagle: @actionshrimp: Ho deciso di eliminare tutti i comandi e le impostazioni relativi alla messa a fuoco. Il mio intento originale era quello di evitare di concentrarsi sui pulsanti disabilitati, ma se questo è quello che costa non ne vale la pena. Senza requestFocus (), clearFocus () o setFocusable (), nessun pulsante mantiene lo stato attivo dopo il ritorno dell'attività secondaria. È il minore di due punteruoli: immagino che dovrò convivere con l'utente in grado di impostare lo stato attivo su un pulsante disabilitato.
InteXX

gli elementi disabilitati non sono attivabili AFAIK ... usa setEnabled (false)
siliconeagle

8

android:descendantFocusability="beforeDescendants"

l'utilizzo di quanto segue nell'attività con alcune opzioni di layout sottostanti sembrava funzionare come desiderato.

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

in connessione con i seguenti parametri nella vista root.

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

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

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

Informazioni su windowSoftInputMode

C'è ancora un altro punto di contesa di cui essere consapevoli. Per impostazione predefinita, Android assegnerà automaticamente lo stato attivo iniziale al primo EditText o controllo attivabile nella tua attività. Ne consegue naturalmente che InputMethod (tipicamente la tastiera virtuale) risponderà all'evento focus mostrandosi. L'attributo windowSoftInputMode in AndroidManifest.xml, se impostato su stateAlwaysHidden, indica alla tastiera di ignorare questo focus iniziale assegnato automaticamente.

<activity
    android:name=".MyActivity"
    android:windowSoftInputMode="stateAlwaysHidden"/>

ottimo riferimento


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 quando ho già finito di aggiornare le informazioni del profilo e rimuovere tutto il focus da EditText nel mio layout

====> Aggiornamento: nel contenuto del layout principale la mia riga di aggiunta EditText:

android:focusableInTouchMode="true"


2

Prima di tutto, funzionerà al 100% ........

  1. Crea onResume()metodo.
  2. All'interno di questo onResume()trova la vista che si sta concentrando ancora e ancora da findViewById().
  3. All'interno di questo onResume()set requestFocus()a questa vista.
  4. All'interno di questo onResume()set clearFocusa questa vista.
  5. Vai in xml dello stesso layout e trova la vista dall'alto su cui vuoi essere focalizzato e imposta focusablevero e focusableInTuchvero.
  6. All'interno di questo onResume()trova la vista dall'alto sopra difindViewById
  7. Dentro questo onResume()set requestFocus()a questa vista alla fine.
  8. E ora divertiti ...

2

Ho provato a disabilitare e abilitare la focalizzazione per la visualizzazione e ha funzionato per me (la messa a fuoco è stata ripristinata):

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

1

Potresti provare a disattivare la capacità dell'attività principale di salvare il suo stato (facendo così dimenticare quale controllo aveva il testo e cosa aveva il focus). Avrai bisogno di un altro modo per ricordare cosa hanno i tuoi EditText e ripopolarli su Resume (). Avvia le tue attività secondarie con startActivityForResult () e crea un gestore onActivityResult () nella tua attività principale che aggiornerà correttamente l'EditText. In questo modo puoi impostare il pulsante corretto su cui vuoi concentrartiResume () e allo stesso tempo ripopolando l'EditText usando un myButton.post (new Runnable () {run () {myButton.requestFocus ();}});

Il metodo View.post () è utile per impostare il focus inizialmente perché quel runnable verrà eseguito dopo che la finestra è stata creata e le cose si sistemano, consentendo al meccanismo di focus di funzionare correttamente in quel momento. Il tentativo di impostare lo stato attivo durante onCreate / Start / Resume () di solito ha problemi, ho trovato.

Nota che questo è pseudo-codice e non testato, ma è una possibile direzione che potresti provare.


Ripensandoci ... prova a usare prima la roba View.post () invece di disattivare lo stato salvato dell'attività. Questo potrebbe fare il trucco per te tutto da solo.
Uncle Code Monkey

Purtroppo non ho più un modo semplice per testarlo per noi. Da allora ho deciso di abbandonare il modello di codice nativo e di utilizzare HTML5 / CSS3 per le app mobili, e quindi ho riorganizzato il mio sistema di conseguenza. Ma grazie per quella che sembra essere una risposta molto approfondita. Ho votato a favore.
InteXX

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

Aggiungili al tuo ViewGroup che include il tuo EditTextView. Funziona correttamente con il mio layout vincolato. Spero che questo aiuto


0

Prova quanto segue (chiamata 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();
    }

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.