Jun 5, 2010

Список с кнопками в Android 2.1

Постановка задачи Задача предельно простая. Нужен список элементов, каждая строка должна содержать название элемента и кнопку (кнопки) для управления этим элементом. В разных местах можно найти отрывочные данные по решению проблем, связанных с этой задачей. Собственно список проблем таков:
  1. При добавлении кнопки в строку перестает работать выделение стоки
  2. Кнопка содержит фон, которые может не вписываться в дизайн списка
  3. Обработка событий от кнопок
Есть разные подходы к решению этих проблем, от простых до очень сложных, некоторые подходы вообще не работают на последних SDK. Далее я приведу те решения, которые я нахожу достаточно простыми в реализации и которые работают на Android SDK 2.1. Проблема с фокусом Сама проблема связана с тем, что кнопка перехватывает на себя фокус. В результате чего не вызывается метод onListItemClick. Решение заключается в изменении атрибута android:descendantFocusability у родительского контейнера (группы, которая содержит кнопку и остальные визуальные компоненты, с помощью которых отображается строка списка). Значение этого атрибута должно быть установлено в blocksDescendants. Фон кнопки Если в качестве кнопки вы используете изображение (ImageButton), то предопределенный фон может сильно портить дизайн списка. Решение тривиально - необходимо установить значение атрибута android:background в @android:color/transparent. Однако это порождает другую проблему. Теперь кнопка визуально не подтверждает нажатие и фокус. Возможно такое поведение может быть приемлемым, но если нет, то необходимо использовать различные рисунки для каждого состояния кнопки:
  1. Создать в папке drawable картинки для каждого состояния кнопки: button_pressed.png, button_focused.png, button_normal.png
  2. Создать в папке 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. Его значение - это строка, которая определяет метод в данном контексте (обычно текущая активность), который будет вызван при нажатии на этот компонент. Для кнопок этот подход тоже работает. Чтобы им воспользоваться необходимо:
  1. В текущей Activity создать публичный метод с одним параметром типа View, например public void onMyButtonClick(View view) {...}
  2. Установить значение атрибута кнопки 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.

No comments: