Як зняти фокус, не встановлюючи фокус на інший елемент керування?


95

Мені подобається, щоб мої інтерфейси були інтуїтивно зрозумілими; кожен екран повинен, природно і ненав’язливо, направляти користувача до наступного кроку в програмі. За винятком цього, я прагну зробити все якомога заплутанішим і незрозумілішим.

Жартую :-)

У мене три TableRows, кожна з яких містить лише для читання та нефокусований елемент керування EditText, а потім кнопку праворуч. Кожна кнопка починає ту саму діяльність, але з різним аргументом. Користувач робить там вибір, а піддіяльність завершує, заповнюючи відповідний EditTextвибір користувачем.

Це класичний механізм каскадних значень; кожен вибір звужує доступні параметри для наступного виділення і т. д. Таким чином, я вимикаю обидва елементи керування в кожному з наступних рядків, поки EditText у поточному рядку не містить значення.

Мені потрібно зробити одну з двох речей, у такому порядку переваг:

  1. Після натискання кнопки негайно зніміть фокус, не встановлюючи фокус на іншу кнопку
  2. Встановіть фокус на першу кнопку, коли починається дія

Проблема проявляється після повернення субдіяльності; натиснута кнопка зберігає фокус.

Re: №1 вище - схоже, не існує removeFocus()методу чи чогось подібного

Re: # 2 вище - я можу використовувати, requestFocus()щоб встановити фокус на кнопку в наступному рядку, і це працює після повернення суб-активності, але чомусь це не працює в батьківській діяльності onCreate().

Мені потрібна узгодженість інтерфейсу користувача в будь-якому напрямку - або жодна кнопка не має фокусу після завершення підзаходу, або кожна кнопка отримує фокус залежно від свого місця в логічному потоці, включаючи саму першу (і єдину) активну кнопку до будь-якого вибору.

Відповіді:


173

Використання clearFocus (), здається, не працювало і для мене, як ви знайшли (бачили в коментарях до іншої відповіді), але в підсумку мені вдалося додати:

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

до мого найвищого рівня Layout View (лінійний макет). Щоб видалити фокус з усіх кнопок / EditTexts тощо, ви можете просто зробити

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

Запит на фокус нічого не робив, якщо я не встановив вид для фокусування.


На мить швидко я подумав, що це може спрацювати. "Який прекрасний у своїй простоті!" Я сказав собі. На жаль, цього не мало бути. Навіть коли я видаляю requestFocus (), кнопка наступного рядка отримує фокус. Це буде нормально як друга перевага, але лише якщо я зможу якось встановити фокус на першу кнопку в onCreate ().
InteXX

@InteXX: Сьогодні я знову зіткнувся з цією проблемою і знайшов рішення. Я знаю, що ти зараз пішов іншим маршрутом, але спробуй, якщо ти ще колись опинишся в тому самому човні!
actionshrimp

"Я знаю, що ти пішов іншим маршрутом зараз" Ще не пізно зробити резервну копію :-) Я спробую і дам вам знати, дякую.
InteXX

Проклятий. Майже, але не зовсім. Так, фокус знімається з останньої натиснутої кнопки, але це також перешкоджає будь-якій кнопці отримати фокус. Це означало б, що мої нечутливі користувачі не зможуть натиснути кнопку. Це те саме робить для вас?
InteXX

6
Це не працюватиме на ScrollView. Якщо ваш вид зверху - ScrollView, використовуйте його для його дочірньої організації.
Uroš Podkrižnik

79

Старе запитання, але я зіткнувся з ним, коли у мене була подібна проблема, і думав поділитися тим, що в підсумку робив.

Погляд, який привертав увагу, щоразу був іншим, тому я використав дуже загальний:

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

12
Елегантний спосіб зробити це. Можливо, ви хочете перевірити, чи немає значення getCurrentFocus (), перш ніж зателефонувати clearFocus ()
Vering

4
+1 Так, вам доведеться кинути цю нульову перевірку! - Чому Java не може просто реалізувати безпечний оператор обходу? Це було б так просто getCurrentFocus()?.clearFocus();, так приємно та елегантно: - /
Левіт

1
@willlma: Так, я мав на увазі саме це.
Верінг

5
@Levit Дуже швидко. :-) Але навіть якби Java реалізувала такого оператора, Android все одно знадобиться 4 роки.
Грег Браун

2
@Levit, ти вже напевно знайшов це, але Котлін.
продає

9
  1. Можна використовувати View.clearFocus().

  2. Використовувати View.requestFocus()виклик від onResume().


@siliconeagle: Зараз це дуже ДУЖЕ. (Дякую за покажчик на clearFocus () btw - я про це не знав.) Коли я натискаю першу кнопку, роблю вибір, а потім повертаюся, перша кнопка вже не може отримувати фокус. Я не встановлюю фокусування для цієї кнопки ніде в коді. Я хотів би показати вам свій код, але в цьому вікні редагування не вистачає символів, і я є новим для SO.
InteXX

@siliconeagle: На жаль, clearFocus () не працює - кнопки зберігають фокус, коли субдіяльність повертається.
InteXX

@siliconeagle: Добре, не зважай на перший коментар. Я використовував setFocusable (false) у події натискання кнопки та забуваючи ввімкнути його знову після повернення підактивності. clearFocus () все ще не має ефекту - цікаво, чому? Я викликаю його на всіх кнопках з onActivityResult (), але натиснута кнопка все ще зберігає фокус. Непарні
InteXX

@siliconeagle: @actionshrimp: Я вирішив покінчити з усіма командами та налаштуваннями, пов’язаними з фокусом. Первісний намір полягав у тому, щоб запобігти зосередженню уваги на відключених кнопочках, але якщо це коштує, це не варто. Без запитуFocus (), clearFocus () або setFocusable (), жодна кнопка не зберігає фокус після повернення підзадачі. Це менше двох довгоносиків - я думаю, мені доведеться жити, коли користувач зможе налаштувати фокус на відключену кнопку.
InteXX

відключені елементи не фокусуються AFAIK ... використовуйте setEnabled (false)
siliconeagle

8

android:descendantFocusability="beforeDescendants"

використання наступного в діяльності з деякими опціями макета нижче, здавалося, працювало за бажанням.

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

у зв'язку з наступними параметрами в кореневому вікні.

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

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

Відповісти завдяки: https://forums.xamarin.com/discussion/1856/how-to-disable-auto-focus-on-edit-text

Про windowSoftInputMode

Є ще одна суперечка, про яку слід пам’ятати. За замовчуванням Android автоматично призначає початковий фокус першому EditText або елементу керування фокусуванням у вашій діяльності. Звичайно випливає, що InputMethod (як правило, програмна клавіатура) реагуватиме на подію фокусування, показуючи себе. Атрибут windowSoftInputMode в AndroidManifest.xml, якщо встановлений у stateAlwaysHidden, вказує клавіатурі ігнорувати цей автоматично присвоєний початковий фокус.

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

чудова довідка


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

Я використовую це, коли вже готову інформацію про оновлення профілю та видаляю всі фокуси з EditText у моєму макеті

====> Оновлення: у змісті батьківського макета мій рядок EditText додає:

android:focusableInTouchMode="true"


2

Перш за все, це працюватиме на 100% ........

  1. onResume()Метод створення .
  2. Всередині цього onResume()знайдіть вигляд, який знову і знову фокусується findViewById().
  3. Всередині цього onResume()набору requestFocus()для цього подання.
  4. Всередині цього onResume()набору clearFocusдля цього подання.
  5. Перейдіть у xml того самого макета і знайдіть той вид зверху, на який ви хочете бути сфокусованим, і встановіть focusabletrue іfocusableInTuch true.
  6. Всередині цього onResume()знайдіть наведений вище вид зверху заfindViewById
  7. Усередині цього onResume()набору requestFocus()нарешті цей вигляд.
  8. А тепер насолоджуйтесь ......

2

Я спробував вимкнути та ввімкнути фокусування для перегляду, і це спрацювало для мене (фокус було скинуто):

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

1

Ви можете спробувати вимкнути можливість основної діяльності зберігати свій стан (тим самим змушуючи її забути, який елемент керування мав текст, а що фокус). Вам потрібно буде мати якийсь інший спосіб запам'ятати, що є у вашому EditText, і повторно заповнити їх уResume (). Запустіть свої підзаходи за допомогою startActivityForResult () і створіть обробник onActivityResult () у вашій головній діяльності, який буде правильно оновлювати текст редагування. Таким чином, ви можете встановити відповідну кнопку, для якої ви хочете зосередитись на Resume (), одночасно із повторним заповненням EditText, використовуючи myButton.post (new Runnable () {run () {myButton.requestFocus ();}});

Метод View. Спроба встановити фокус під час onCreate / Start / Resume () зазвичай має проблеми, я виявив.

Зверніть увагу, що це псевдокод і не перевірений, але це можливий напрямок, який ви можете спробувати.


Якщо добре подумати ... спробуйте спочатку просто скористатися матеріалами View.post (), замість того, щоб вимикати збережений стан Activity. Це може зробити трюк для вас само собою.
Uncle Code Monkey

На жаль, у мене вже немає простого способу перевірити це для нас. З тих пір я вирішив відмовитись від рідної моделі коду та піти на HTML5 / CSS3 для мобільних додатків, і, отже, переосмислив мою систему відповідно. Але дякую за те, що видається дуже глибокою відповіддю. Я проголосував.
InteXX

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

Додайте їх до групи ViewGroup, що включає EditTextView. Він правильно працює з моїм макетом обмежень. Сподіваюся, це допоможе


0

Спробуйте наступне (дзвінок 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();
    }

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.