Я провел приблизительно 6 часов на это до сих пор и был ударом только контрольно-пропускные пункты. Общая предпосылка - то, что существует некоторая строка в a ListView
(сгенерировано ли это адаптером или добавлено как представление заголовка), который содержит EditText
виджет и a Button
. Все, что я хочу сделать, смочь использовать jogball/arrows, переместиться по селектору к отдельным объектам как нормальный, но когда я добираюсь до конкретной строки - даже если я должен явно определить строку - который имеет focusable ребенка, я хочу, чтобы тот ребенок взял фокус вместо того, чтобы указать на положение с селектором.
Я попробовал много возможностей и до сих пор не имел никакой удачи.
расположение:
<ListView
android:id="@android:id/list"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
/>
Представление Header:
EditText view = new EditText(this);
listView.addHeaderView(view, null, true);
Принятие там является другими объектами в адаптере, использование клавиш со стрелками переместит выбор/вниз в список, как ожидалось; но при получении до строки заголовка, это также отображено с селектором и никаким способом сфокусироваться в EditText
использование jogball.Примечание: ответвление на EditText
сфокусирует его в той точке, однако который полагается на сенсорный экран, который не должен быть требованием.
ListView
по-видимому, имеет два режима в этом отношении:
1. setItemsCanFocus(true)
: селектор никогда не отображается, но EditText
может получить фокус при использовании стрелок. Сфокусируйтесь алгоритм поиска трудно предсказать, и никакая визуальная обратная связь (на любых строках: наличие focusable детей или не), на котором выбран объект, оба из которых могут дать пользователю неожиданный опыт.
2. setItemsCanFocus(false)
: селектор всегда оттягивается в несенсорном режиме, и EditText
никогда не может получать фокус - даже если Вы касаетесь на нем.
Усугублять положение, звоня editTextView.requestFocus()
возвращает true, но на самом деле не дает фокус EditText.
То, что я предполагаю, является в основном гибридом 1 и 2, где, а не установка списка, если все объекты focusable или нет, я хочу установить focusability для единственного объекта в списке, так, чтобы селектор беспрепятственно перешел от выбора всей строки для non-focusable объектов и пересечения дерева фокуса для объектов, которые содержат focusable дочерние элементы.
Какие-либо берущие?
Извините, сам ответил на свой вопрос. Возможно, это не самое правильное или элегантное решение, но оно работает для меня, и дает довольно солидный пользовательский опыт. Я заглянул в код ListView, чтобы понять, почему эти два поведения настолько различны, и наткнулся на следующее из ListView.java:
public void setItemsCanFocus(boolean itemsCanFocus) {
mItemsCanFocus = itemsCanFocus;
if (!itemsCanFocus) {
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
}
Итак, при вызове setItemsCanFocus(false)
, он также устанавливает фокусируемость потомков, так что ни один ребенок не может получить фокус. Это объясняет, почему я не мог просто переключить mItemsCanFocus
в OnItemSelectedListener ListView - потому что ListView тогда блокировал фокус для всех дочерних элементов.
Что у меня сейчас:
<ListView
android:id="@android:id/list"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:descendantFocusability="beforeDescendants"
/>
Я использую beforeDescendants
, потому что селектор будет рисоваться только тогда, когда сам ListView (не дочерний элемент) имеет фокус, поэтому поведение по умолчанию должно быть таким, что ListView первым получает фокус и рисует селекторы.
Затем в OnItemSelectedListener, поскольку я знаю, какое представление заголовка я хочу переопределить селектор (потребовалось бы больше работы, чтобы динамически определить, содержит ли любая данная позиция фокусируемое представление), я могу изменить фокусируемость потомков и установить фокус на EditText. А когда я выйду из этого заголовка, снова изменить фокус.
public void onItemSelected(AdapterView<?> listView, View view, int position, long id)
{
if (position == 1)
{
// listView.setItemsCanFocus(true);
// Use afterDescendants, because I don't want the ListView to steal focus
listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
myEditText.requestFocus();
}
else
{
if (!listView.isFocused())
{
// listView.setItemsCanFocus(false);
// Use beforeDescendants so that the EditText doesn't re-take focus
listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
listView.requestFocus();
}
}
}
public void onNothingSelected(AdapterView<?> listView)
{
// This happens when you start scrolling, so we need to prevent it from staying
// in the afterDescendants mode if the EditText was focused
listView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
Обратите внимание на закомментированные вызовы setItemsCanFocus
. С помощью этих вызовов я получил правильное поведение, но setItemsCanFocus(false)
заставлял фокус перескакивать с EditText на другой виджет вне ListView, обратно в ListView и отображал селектор на следующем выбранном элементе, и это перескакивание фокуса отвлекало. Убрав изменение ItemsCanFocus и просто переключив фокусируемость потомков, я добился желаемого поведения. Все элементы рисуют селектор как обычно, но при переходе к строке с EditText он фокусируется на текстовом поле. Затем, при выходе из этого EditText, он снова начал рисовать селектор.