Постановка задачи
Задача предельно простая. Нужен список элементов, каждая строка должна содержать название элемента и кнопку (кнопки) для управления этим элементом. В разных местах можно найти отрывочные данные по решению проблем, связанных с этой задачей. Собственно список проблем таков:
- При добавлении кнопки в строку перестает работать выделение стоки
- Кнопка содержит фон, которые может не вписываться в дизайн списка
- Обработка событий от кнопок
Есть разные подходы к решению этих проблем, от простых до очень сложных, некоторые подходы вообще не работают на последних SDK. Далее я приведу те решения, которые я нахожу достаточно простыми в реализации и которые работают на Android SDK 2.1.
Проблема с фокусом
Сама проблема связана с тем, что кнопка перехватывает на себя фокус. В результате чего не вызывается метод onListItemClick. Решение заключается в изменении атрибута android:descendantFocusability у родительского контейнера (группы, которая содержит кнопку и остальные визуальные компоненты, с помощью которых отображается строка списка). Значение этого атрибута должно быть установлено в blocksDescendants.
Фон кнопки
Если в качестве кнопки вы используете изображение (ImageButton), то предопределенный фон может сильно портить дизайн списка. Решение тривиально - необходимо установить значение атрибута android:background в @android:color/transparent. Однако это порождает другую проблему. Теперь кнопка визуально не подтверждает нажатие и фокус. Возможно такое поведение может быть приемлемым, но если нет, то необходимо использовать различные рисунки для каждого состояния кнопки:
- Создать в папке drawable картинки для каждого состояния кнопки: button_pressed.png, button_focused.png, button_normal.png
- Создать в папке drawable специальны XML файл, который будет выбирать изображение для каждого состояния (селектор), возможное содержимое этого файла привожу ниже
button_selector.xml:
xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android">
android:state_pressed="true"
android:drawable="@drawable/button_pressed" />
android:state_focused="true"
android:drawable="@drawable/button_focused" />
android:drawable="@drawable/button_normal" />
Более подробно можно почитать в документации по ImageButton.
Обработка событий
Здесь я использовал следующий подход. Каждый компонент типа View содержит атрибут android:onClick. Его значение - это строка, которая определяет метод в данном контексте (обычно текущая активность), который будет вызван при нажатии на этот компонент. Для кнопок этот подход тоже работает. Чтобы им воспользоваться необходимо:
- В текущей Activity создать публичный метод с одним параметром типа View, например public void onMyButtonClick(View view) {...}
- Установить значение атрибута кнопки android:onClick в "onMyButtonClick"
Открытым остался вопрос, а как же определить, какая именно кнопка была нажата?
Тут тоже можно идти разными путями, но я выбрал использование собственной реализации интерфейса SimpleCursorAdapter.ViewBinder. С его помощью я помещаю ID текущего элемента списка в Tag кнопки. Выглядит это примерно следующим образом: private final class ItemRowBinder implements SimpleCursorAdapter.ViewBinder {
private static final String TAG = "ItemRowBinder";
@Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
switch (view.getId()) {
case R.id.ImageButtonDelete: {
view.setTag(Long.valueOf(cursor.getLong(columnIndex)));
return true;
}
}
return false;
}
}
Конечно надо не забыть указать привязку поля с ID и компонента кнопки в конструкторе SimpleCursorAdapter.