Jak usunąć fokus bez ustawiania fokusu na inną kontrolkę?


98

Lubię, gdy moje interfejsy użytkownika są intuicyjne; każdy ekran powinien w naturalny i dyskretny sposób prowadzić użytkownika do następnego kroku w aplikacji. Poza tym staram się, aby rzeczy były jak najbardziej zagmatwane i zagmatwane.

Żartuję :-)

Mam trzy TableRows, z których każdy zawiera tylko do odczytu i nie można fokusować kontrolkę EditText, a następnie przycisk po jej prawej stronie. Każdy przycisk uruchamia to samo działanie, ale z innym argumentem. Użytkownik dokonuje w tym miejscu wyboru, a działanie podrzędne kończy, wypełniając odpowiednie EditTextzaznaczeniem użytkownika.

To klasyczny mechanizm kaskadowych wartości; każde zaznaczenie zawęża dostępne opcje dla następnego zaznaczenia, itp. Dlatego wyłączam obie kontrolki w każdym z następnych wierszy, dopóki EditText w bieżącym wierszu nie będzie zawierała wartości.

Muszę zrobić jedną z dwóch rzeczy, w następującej kolejności:

  1. Po kliknięciu przycisku natychmiast usuń fokus bez ustawiania fokusu na inny przycisk
  2. Po rozpoczęciu działania ustaw fokus na pierwszy przycisk

Problem objawia się po powrocie poddziałania; kliknięty przycisk zachowuje fokus.

Re: # 1 powyżej - Wygląda na to removeFocus(), że nie ma metody ani czegoś podobnego

Re: # 2 powyżej - mogę użyć, requestFocus()aby ustawić fokus na przycisk w następnym wierszu, który działa po powrocie działania podrzędnego, ale z jakiegoś powodu nie działa w działaniu nadrzędnym onCreate().

Potrzebuję spójności interfejsu użytkownika w dowolnym kierunku - albo żaden przycisk nie jest aktywny po zakończeniu działania podrzędnego, albo każdy przycisk otrzymuje fokus w zależności od jego miejsca w przepływie logiki, w tym pierwszego (i jedynego) aktywnego przycisku przed jakimkolwiek wyborem.

Odpowiedzi:


178

Używanie clearFocus () również nie wydawało się działać dla mnie, jak znalazłeś (zobaczyłeś w komentarzach do innej odpowiedzi), ale ostatecznie zadziałało dla mnie dodanie:

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

do mojego widoku układu najwyższego poziomu (układ liniowy). Aby usunąć fokus ze wszystkich Buttons / EditTexts itp., Możesz po prostu zrobić

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

Prośba o skupienie nic nie dała, chyba że ustawiłem widok jako możliwy do skupienia.


Przez krótką chwilę myślałem, że to może zadziałać. „Jak piękna w swojej prostocie!” Powiedziałem sam do siebie. Niestety, tak się nie stało. Nawet gdy usuwam requestFocus (), przycisk następnego wiersza staje się aktywny. Byłoby to OK jako druga preferencja, ale tylko wtedy, gdybym mógł w jakiś sposób ustawić fokus na pierwszym przycisku w onCreate ().
InteXX

@InteXX: Dzisiaj ponownie natknąłem się na ten problem i znalazłem rozwiązanie. Wiem, że popłynąłeś teraz inną trasą, ale spróbuj, jeśli kiedykolwiek znowu znajdziesz się na tej samej łodzi!
actionshrimp

„Wiem, że poszedłeś teraz inną drogą” Nadal nie jest za późno na tworzenie kopii zapasowych :-) Spróbuję i dam znać, dzięki.
InteXX

Cerować. Prawie, ale nie do końca. Tak, zdejmuje fokus z przycisku, który został kliknięty jako ostatni, ale także zapobiega temu, aby ŻADEN przycisk nie uzyskał ostrości. Oznaczałoby to, że moi użytkownicy niedotykowi nie mogliby kliknąć przycisku. Czy robi to samo dla Ciebie?
InteXX

6
To nie zadziała w ScrollView. Jeśli twój widok z góry to ScrollView, użyj tego na jego potomku.
Uroš Podkrižnik

81

Stare pytanie, ale natknąłem się na nie, gdy miałem podobny problem i pomyślałem, że podzielę się tym, co ostatecznie zrobiłem.

Widok, który przykuwał uwagę, był za każdym razem inny, więc użyłem bardzo ogólnego:

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

12
Elegancki sposób na zrobienie tego. Przed wywołaniem clearFocus () warto sprawdzić wartość zerową z getCurrentFocus ()
Vering

4
+1 Tak, będziesz musiał dorzucić ten zerowy czek! - Dlaczego Java nie może po prostu zaimplementować operatora bezpiecznego przechodzenia? To byłoby tak proste, jak getCurrentFocus()?.clearFocus();, takie ładne i eleganckie: - /
Levite

1
@willlma: Tak, dokładnie to miałem na myśli.
Vering

5
@Levit Bardzo szybki jak. :-) Ale nawet gdyby Java zaimplementowała takiego operatora, Androidowi zajęłoby to 4 lata.
Greg Brown

2
@Levit, prawdopodobnie już go znalazłeś, ale Kotlin.
prodaea

9
  1. Możesz użyć View.clearFocus().

  2. Użyj View.requestFocus()wywoływanego z onResume().


@siliconeagle: To jest BARDZO dziwne. (Dzięki za wskaźnik do clearFocus () btw - nie byłem tego świadomy.) Kiedy klikam pierwszy przycisk, dokonuję wyboru, a potem wracam, pierwszy przycisk nie może już być aktywny. Nie ustawiam fokusu dla tego przycisku w żadnym miejscu w moim kodzie. Chciałbym pokazać Ci mój kod, ale w tym oknie edycji nie ma wystarczającej liczby znaków i jestem nowy w SO Nie jestem pewien, czy powinienem wpisać inną odpowiedź tylko po to, aby móc wysłać kod.
InteXX

@siliconeagle: Niestety, clearFocus () nie działa - przyciski zachowują fokus po powrocie poddziałania.
InteXX,

@siliconeagle: OK, nieważne o tym pierwszym komentarzu. Używałem setFocusable (false) w zdarzeniu kliknięcia przycisku i zapomniałem go włączyć po powrocie pod-działania. Funkcja clearFocus () nadal jednak nie działa - zastanawiam się, dlaczego? Wywołuję to dla wszystkich przycisków z onActivityResult (), ale kliknięty przycisk nadal zachowuje fokus. Dziwny.
InteXX

@siliconeagle: @actionshrimp: Postanowiłem pozbyć się wszystkich poleceń i ustawień związanych z fokusem. Moim pierwotnym zamiarem było zapobieganie skupianiu się na wyłączonych przyciskach, ale jeśli to kosztuje, to nie jest tego warte. Bez requestFocus (), clearFocus () lub setFocusable (), żaden przycisk nie zachowuje fokusu po powrocie poddziałania. Jest to mniejszy z dwóch wołków - myślę, że będę musiał żyć z użytkownikiem, który będzie mógł ustawić fokus na wyłączony przycisk.
InteXX

Elementy są niepełnosprawni nie aktywowana AFAIK ... stosowanie setEnabled (fałsz)
siliconeagle

9

android:descendantFocusability="beforeDescendants"

użycie następujących elementów w ćwiczeniu z niektórymi opcjami układu poniżej wydawało się działać zgodnie z oczekiwaniami.

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

w połączeniu z następującymi parametrami w widoku głównym.

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

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

Odpowiedz dzięki: https://forums.xamarin.com/discussion/1856/how-to-disable-auto-focus-on-edit-text

Informacje o windowSoftInputMode

Jest jeszcze jeden punkt sporny, o którym należy pamiętać. Domyślnie system Android automatycznie przypisuje początkowy fokus do pierwszego tekstu edycji lub kontrolki, na którą można ustawić fokus w Twoim działaniu. Wynika z tego naturalnie, że InputMethod (zazwyczaj klawiatura miękka) zareaguje na zdarzenie fokusu, wyświetlając się. Atrybut windowSoftInputMode w AndroidManifest.xml, gdy jest ustawiony na stateAlwaysHidden, instruuje klawiaturę, aby zignorowała ten automatycznie przypisany początkowy fokus.

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

świetne odniesienie


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

Używam tego, gdy już skończyłem aktualizować informacje o profilu i usuwam cały fokus z EditText w moim układzie

====> Aktualizacja: W treści układu nadrzędnego moja linia dodawania EditText:

android:focusableInTouchMode="true"


3

Próbowałem wyłączyć i włączyć możliwość ustawiania ostrości dla widoku i to działało dla mnie (ostrość została zresetowana):

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

2

Przede wszystkim sprawdzi się w 100% ........

  1. Stwórz onResume() metodę.
  2. Wewnątrz tego onResume()znajdź widok, który ciągle się skupiafindViewById() .
  3. Wewnątrz tego onResume()zestawurequestFocus() do tego widoku.
  4. Wewnątrz tego onResume()zestawuclearFocus do tego widoku.
  5. Przejdź do XML o tym samym układzie i znajdź widok z góry, na którym chcesz się skupić i ustawić jako focusableprawdziwy ifocusableInTuch prawdziwy.
  6. Wewnątrz onResume()znajdź powyższy widok z góry wgfindViewById
  7. Wewnątrz tego onResume()zestawurequestFocus() do tego widoku w końcu.
  8. A teraz ciesz się ......

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

Dodaj je do swojej ViewGroup, która zawiera EditTextView. Działa poprawnie z moim układem ograniczeń. Mam nadzieję, że to pomoże


1

Możesz spróbować wyłączyć zdolność głównego działania do zapisywania jego stanu (w ten sposób zapominając, która kontrolka miała tekst, a na czym była fokus). Będziesz musiał mieć inny sposób zapamiętania tego, co ma twój EditText i ponownego zapełnienia ich wResume (). Uruchom swoje poddziałania za pomocą startActivityForResult () i utwórz procedurę obsługi onActivityResult () w głównym działaniu, które poprawnie zaktualizuje EditText. W ten sposób możesz ustawić odpowiedni przycisk, na którym chcesz skupić się naResume (), w tym samym czasie, gdy ponownie zapełniasz EditText używając myButton.post (new Runnable () {run () {myButton.requestFocus ();}});

Metoda View.post () jest przydatna do początkowego ustawiania fokusu, ponieważ ten element uruchamiający zostanie wykonany po utworzeniu okna i ustabilizowaniu się, umożliwiając mechanizmowi fokusu prawidłowe działanie do tego czasu. Próbowałem ustawić fokus podczas onCreate / Start / Resume (), co zwykle powoduje problemy.

Pamiętaj, że jest to pseudokod i nie został przetestowany, ale jest to możliwy kierunek, w którym możesz spróbować.


Po zastanowieniu ... spróbuj najpierw użyć funkcji View.post () zamiast wyłączać zapisany stan działania. To może samo załatwić sprawę.
Uncle Code Monkey,

Niestety, nie mam już łatwego sposobu na przetestowanie tego dla nas. Od tego czasu zdecydowałem się porzucić natywny model kodu i przejść do HTML5 / CSS3 dla aplikacji mobilnych, a tym samym odpowiednio przeprojektowałem mój system. Ale dziękuję za to, co wydaje się bardzo szczegółową odpowiedzią. Głosowałem za tym.
InteXX,

0

Wypróbuj następujące (dzwonienie 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();
    }

}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.