Wie entferne ich den Fokus, ohne den Fokus auf ein anderes Steuerelement zu setzen?

93

Ich mag es, wenn meine Benutzeroberflächen intuitiv sind. Jeder Bildschirm sollte den Benutzer natürlich und unauffällig zum nächsten Schritt in der App führen. Ansonsten bemühe ich mich, die Dinge so verwirrend und verwirrend wie möglich zu gestalten.

Ich mache nur Spaß :-)

Ich habe drei TableRowSekunden, die jeweils ein schreibgeschütztes und nicht fokussierbares EditText-Steuerelement und dann eine Schaltfläche rechts davon enthalten. Jede Schaltfläche startet dieselbe Aktivität, jedoch mit einem anderen Argument. Der Benutzer trifft dort eine Auswahl, und die Unteraktivität wird beendet, wobei die entsprechende EditTextAuswahl mit der Auswahl des Benutzers gefüllt wird.

Es ist der klassische Mechanismus für kaskadierende Werte. Jede Auswahl schränkt die verfügbaren Optionen für die nächste Auswahl usw. ein. Daher deaktiviere ich beide Steuerelemente in jeder der nächsten Zeilen, bis der EditText in der aktuellen Zeile einen Wert enthält.

Ich muss eines von zwei Dingen in dieser Reihenfolge tun:

  1. Wenn Sie auf eine Schaltfläche klicken, entfernen Sie sofort den Fokus, ohne den Fokus auf eine andere Schaltfläche zu setzen
  2. Stellen Sie den Fokus auf die erste Schaltfläche, wenn die Aktivität beginnt

Das Problem tritt auf, nachdem die Unteraktivität zurückgekehrt ist. Die Schaltfläche, auf die geklickt wurde, behält den Fokus.

Betreff: Nr. 1 oben - Es scheint keine removeFocus()Methode oder ähnliches zu geben

Betreff: # 2 oben - Ich kann requestFocus()den Fokus auf die Schaltfläche in der nächsten Zeile setzen, und das funktioniert, nachdem die Unteraktivität zurückgekehrt ist, aber aus irgendeinem Grund funktioniert es nicht in der übergeordneten Aktivität onCreate().

Ich benötige Konsistenz der Benutzeroberfläche in beide Richtungen - entweder haben keine Schaltflächen nach Abschluss der Unteraktivität den Fokus oder jede Schaltfläche erhält den Fokus abhängig von ihrer Position im Logikfluss, einschließlich der allerersten (und einzigen) aktiven Schaltfläche vor einer Auswahl.

InteXX
quelle

Antworten:

173

Die Verwendung von clearFocus () schien auch nicht für mich zu funktionieren, wie Sie festgestellt haben (siehe Kommentare zu einer anderen Antwort), aber was am Ende für mich funktionierte, war das Hinzufügen von:

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

zu meiner obersten Ebene Layoutansicht (ein lineares Layout). Um den Fokus von allen Schaltflächen / EditTexts usw. zu entfernen, können Sie dies einfach tun

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

Das Anfordern des Fokus hat nichts bewirkt, es sei denn, ich habe die Ansicht so eingestellt, dass sie fokussierbar ist.

Actionshrimp
quelle
Für einen flüchtigen Moment dachte ich, das könnte funktionieren. "Wie schön in seiner Einfachheit!" Ich sagte zu mir. Leider sollte es nicht sein. Selbst wenn ich requestFocus () entferne, wird die Schaltfläche der nächsten Zeile fokussiert. Dies wäre als zweite Einstellung in Ordnung, aber nur, wenn ich mich irgendwie auf die erste Schaltfläche in onCreate () konzentrieren kann.
InteXX
@InteXX: Ich bin heute wieder auf dieses Problem gestoßen und habe eine Lösung gefunden. Ich weiß, dass Sie jetzt einen anderen Weg gegangen sind, aber probieren Sie es aus, wenn Sie sich jemals wieder im selben Boot befinden!
Actionshrimp
"Ich weiß, dass du jetzt einen anderen Weg gegangen bist." Es ist immer noch nicht zu spät, um ein Backup zu erstellen :-) Ich werde es versuchen und dich wissen lassen, danke.
InteXX
Verflixt. Fast, aber nicht ganz. Ja, der Fokus wird von der zuletzt angeklickten Schaltfläche entfernt, aber es wird auch verhindert, dass JEDE Schaltfläche den Fokus erhält. Dies würde bedeuten, dass meine Nicht-Touch-Benutzer nicht auf eine Schaltfläche klicken können. Tut es dasselbe für dich?
InteXX
6
Dies funktioniert in ScrollView nicht. Wenn Ihre Draufsicht ScrollView ist, verwenden Sie diese für das untergeordnete Element.
Uroš Podkrižnik
79

Alte Frage, aber ich bin darauf gestoßen, als ich ein ähnliches Problem hatte und dachte, ich würde teilen, was ich letztendlich getan habe.

Die Ansicht, die den Fokus gewann, war jedes Mal anders, also benutzte ich die sehr allgemeine:

View current = getCurrentFocus();
if (current != null) current.clearFocus();
willlma
quelle
12
Elegante Art dies zu tun. Man könnte einen Wert von getCurrentFocus () auf null prüfen wollen, bevor man clearFocus () aufruft
Vering
4
+1 Ja, Sie müssen diesen Null-Check einwerfen! - Warum kann Java nicht einfach einen Safe-Traversal-Operator implementieren? Es wäre so einfach wie getCurrentFocus()?.clearFocus();, so schön und elegant: - /
Levite
1
@willlma: Ja, genau das habe ich gemeint.
Vering
5
@Levit Sehr schnell. :-) Aber selbst wenn Java einen solchen Operator implementieren würde, würde Android noch 4 Jahre brauchen, um aufzuholen.
Greg Brown
2
@Levit, du hast es wahrscheinlich schon gefunden, aber Kotlin.
Prodaea
9
  1. Sie können verwenden View.clearFocus().

  2. Verwenden Sie View.requestFocus()aufgerufen von onResume().

siliconeagle
quelle
@ Siliconeagle: Nun, das ist sehr seltsam. (Danke übrigens für den Zeiger auf clearFocus () - das war mir nicht bewusst.) Wenn ich auf die erste Schaltfläche klicke, eine Auswahl treffe und dann zurückkehre, kann die erste Schaltfläche keinen Fokus mehr erhalten. Ich bin für diese Schaltfläche an keiner Stelle in meinem Code fokussierbar. Ich möchte Ihnen meinen Code zeigen, aber in diesem Bearbeitungsfenster sind nicht genügend Zeichen verfügbar, und ich bin mir nicht sicher, ob ich eine andere Antwort eingeben soll, um Code veröffentlichen zu können.
InteXX
@siliconeagle: Leider funktioniert clearFocus () nicht - die Schaltflächen behalten den Fokus, wenn die Unteraktivität zurückkehrt.
InteXX
@siliconeagle: OK, egal, dieser erste Kommentar. Ich habe setFocusable (false) im Klickereignis der Schaltfläche verwendet und vergessen, es nach der Rückkehr der Unteraktivität wieder einzuschalten. clearFocus () hat aber immer noch keine Wirkung - ich frage mich warum? Ich rufe es auf allen Schaltflächen von onActivityResult () auf, aber die angeklickte Schaltfläche behält weiterhin den Fokus. Seltsam.
InteXX
@siliconeagle: @actionshrimp: Ich habe beschlossen, alle fokusbezogenen Befehle und Einstellungen abzuschaffen. Meine ursprüngliche Absicht war es, den Fokus auf deaktivierte Schaltflächen zu verhindern, aber wenn es das kostet, lohnt es sich nicht. Ohne requestFocus (), clearFocus () oder setFocusable () behält keine Schaltfläche den Fokus, nachdem die Unteraktivität zurückgekehrt ist. Es ist der kleinere von zwei Rüsselkäfern - ich denke, ich muss damit leben, dass der Benutzer den Fokus auf eine deaktivierte Schaltfläche setzen kann.
InteXX
deaktivierte Elemente sind nicht fokussierbar AFAIK ... benutze setEnabled (false)
siliconeagle
8

android:descendantFocusability="beforeDescendants"

Die Verwendung des Folgenden in der Aktivität mit einigen Layoutoptionen unten schien wie gewünscht zu funktionieren.

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

in Verbindung mit den folgenden Parametern in der Stammansicht.

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

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

Antwort dank: https://forums.xamarin.com/discussion/1856/how-to-disable-auto-focus-on-edit-text

Informationen zu windowSoftInputMode

Es gibt noch einen weiteren Streitpunkt, den Sie beachten sollten. Standardmäßig weist Android dem ersten EditText oder dem fokussierbaren Steuerelement in Ihrer Aktivität automatisch den anfänglichen Fokus zu. Daraus folgt natürlich, dass die InputMethod (normalerweise die Softtastatur) auf das Fokusereignis reagiert, indem sie sich selbst zeigt. Das windowSoftInputMode-Attribut in AndroidManifest.xml weist die Tastatur an, diesen automatisch zugewiesenen Anfangsfokus zu ignorieren, wenn es auf stateAlwaysHidden gesetzt ist.

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

tolle Referenz

CrandellWS
quelle
5
<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();

Ich verwende dies, wenn die Aktualisierung der Profilinformationen bereits abgeschlossen ist, und entferne den gesamten Fokus von EditText in meinem Layout

====> Update: Im übergeordneten Layoutinhalt meine EditText-Zeile hinzufügen:

android:focusableInTouchMode="true"
Ho Luong
quelle
3

Wie wäre es, wenn Sie nur android:windowSoftInputMode="stateHidden"Ihre Aktivität im Manifest hinzufügen?

Entnommen von einem klugen Mann, der dies kommentiert: https://stackoverflow.com/a/2059394/956975

Marienke
quelle
2

Zuallererst wird es 100% funktionieren ........

  1. onResume()Methode erstellen .
  2. Darin onResume()finden Sie die Ansicht, die immer wieder durch fokussiert findViewById().
  3. In diesem onResume()Set requestFocus()auf diese Ansicht.
  4. In diesem onResume()Set clearFocusauf diese Ansicht.
  5. Gehen Sie in XML mit demselben Layout und suchen Sie die Draufsicht, auf die Sie sich konzentrieren möchten, und setzen Sie focusabletrue und focusableInTuchtrue.
  6. Darin onResume()finden Sie die obige Draufsicht vonfindViewById
  7. In diesem onResume()Set requestFocus()auf diese Ansicht zuletzt setzen.
  8. Und jetzt viel Spaß ......
Vishambar Pandey
quelle
2

Ich habe versucht, die Fokussierbarkeit für die Ansicht zu deaktivieren und zu aktivieren, und es hat bei mir funktioniert (Fokus wurde zurückgesetzt):

focusedView.setFocusable(false);
focusedView.setFocusableInTouchMode(false);
focusedView.setFocusable(true);
focusedView.setFocusableInTouchMode(true);
Serhiy
quelle
1

Sie können versuchen, die Fähigkeit der Hauptaktivität zum Speichern ihres Status auszuschalten (wodurch vergessen wird, welches Steuerelement Text und welches Fokus hatte). Sie müssen sich auf andere Weise merken, was Ihre EditText-Dateien haben, und sie auf Resume () neu füllen. Starten Sie Ihre Unteraktivitäten mit startActivityForResult () und erstellen Sie in Ihrer Hauptaktivität einen onActivityResult () -Handler, der die EditText-Dateien korrekt aktualisiert. Auf diese Weise können Sie die richtige Schaltfläche festlegen, die Sie auf Resume () fokussieren möchten, während Sie die EditText-Dateien mithilfe eines myButton.post (new Runnable () {run () {myButton.requestFocus ();}} neu füllen.

Die View.post () -Methode ist nützlich, um den Fokus zunächst festzulegen, da diese ausführbare Datei ausgeführt wird, nachdem das Fenster erstellt wurde und sich die Dinge beruhigt haben, sodass der Fokusmechanismus zu diesem Zeitpunkt ordnungsgemäß funktioniert. Der Versuch, den Fokus während onCreate / Start / Resume () zu setzen, hat normalerweise Probleme.

Bitte beachten Sie, dass dies Pseudocode ist und nicht getestet wurde, aber es ist eine mögliche Richtung, die Sie versuchen könnten.

Onkel Code Affe
quelle
Beim zweiten Gedanken ... versuchen Sie zuerst, das View.post () -Ding zu verwenden, anstatt den gespeicherten Status der Aktivität zu deaktivieren. Das könnte den Trick für Sie alleine tun.
Onkel Code Monkey
Leider habe ich keine einfache Möglichkeit mehr, dies für uns zu testen. Seitdem habe ich mich entschlossen, das native Codemodell aufzugeben und HTML5 / CSS3 für mobile Apps zu verwenden, und mein System daher entsprechend umgerüstet. Aber danke für die scheinbar sehr ausführliche Antwort. Ich habe dafür gestimmt.
InteXX
1
android:focusableInTouchMode="true"
android:focusable="true"
android:clickable="true"

Fügen Sie sie Ihrer ViewGroup hinzu, die Ihre EditTextView enthält. Es funktioniert ordnungsgemäß für mein Einschränkungslayout. Ich hoffe das hilft

Tánh Lee
quelle
0

Versuchen Sie Folgendes (anrufen 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();
    }

}
5chw4hn
quelle