Android списки с группами

ExpandableListView

Компонент ExpandableListView является расширенным вариантом компонента ListView. Основное отличие — разворачивающий список второго уровня. Получается список в списке. Рассмотрим простейший вариант:

Сам по себе компонент не представляет интереса. Его необходимо заполнить данными. Переключимся в код активности и напишем следующее:

Сначала мы описываем массивы данных – это названия групп (Времена года) и названия элементов для них (месяцы).

Затем описываем коллекцию для групп, коллекции для элементов и Map для атрибутов.

В методе onCreate() заполняем groupData. Это коллекция групп. Каждая группа представляет собой Map. А в Map мы пишем необходимые нам атрибуты для каждой группы. В нашем случае, для каждой группы мы укажем всего один атрибут groupName — это название из массива groups.

Адаптер обычно использует layout-ресурс для отображения пункта списка. В нашем случае пунктами ExpandableListView являются и группа и элемент. В layout-ресурсе могут быть какие-либо TextView. Мы можем заполнить их значениями из атрибутов элементов или групп, которые собраны в Map. Для этого нам надо указать сначала имена атрибутов, которые хотим использовать, а затем идентификаторы TextView, в которые хотим поместить значения этих атрибутов.

Для связки атрибутов и TextView мы используем два массива:

  • groupFrom – список имен атрибутов, которые будут считаны. В нашем случае – это groupName, который мы добавили к группе с помощью Map чуть выше в коде, когда собирали группы в groupData.
  • groupTo – список ID View-элементов, в которые будут помещены считанные значения атрибутов. Наш используемый layout будет содержать TextView с >Два этих массива сопоставляются по порядку элементов. В итоге, в layout-ресурсе группы найдется элемент с ID = android.R.id.text1 и в него запишется текст из атрибута groupName. Тем самым мы получим отображение имени группы в списке.

Далее формируем коллекции элементов. Создаем общую коллекцию коллекций. А затем создаем коллекции элементов каждой группы. Принцип тот же, что и с группами – создаем Map и в него пишем атрибут monthName со значением равным имени элемента. Коллекцию элементов для каждой группы добавляем в общую коллекцию.

Формируем два массива для сопоставления TextView из layout и атрибутов элементов. Полностью аналогично, как выше мы уже проделали с группами. В итоге при отображении элемента, найдется TextView с ID = android.R.id.text1 и туда запишется текст из атрибута monthName. И мы увидим текст нашего элемента (месяца) в списке.

В конце кода создаем адаптер SimpleExpandableListAdapter и присваиваем его списку.

Параметры для адаптера:

  • this – контекст
  • groupData – коллекция групп
  • android.R.layout.simple_expandable_list_item_1 – layout-ресурс, который будет использован для отображения группы в списке. Соответственно, запросто можно использовать свой layout-файл
  • groupFrom – массив имен атрибутов групп
  • groupTo – массив ID TextView из layout для групп
  • childData – коллекция коллекций элементов по группам
  • android.R.layout.simple_list_item_1 — layout-ресурс, который будет использован для отображения элемента в списке. Можно использовать свой layout-файл childFrom – массив имен атрибутов элементов
  • childTo — массив ID TextView из layout для элементов

Layout simple_expandable_list_item_1, который мы использовали для отображения групп – это TextView с отступом от левого края, чтобы осталось место для кнопки раскрытия/сворачивания списка. Для эксперимента вы можете попробовать использовать для групп layout simple_list_item_1, который мы использовали для элементов. В этом случае текст будет пересекаться с кнопкой.

А вообще вы можете создать для элементов свою разметку, например, с тремя TextView. И к каждому элементу списка (Map) добавить еще по два атрибута. Далее указываете вашу разметку в конструкторе, формируете соответственно массивы childFrom и childTo чтобы сопоставить атрибуты и TextView, и получится, что каждый элемент группы содержит более подробную информацию.

ExpandableListView редко используется в составе разметки с другими элементами. Обычно такой список занимает весь экран, поэтому для подобных целей лучше использовать специальный класс ExpandableListViewActivity, который уже содержит в своём составе компонент ExpandableListView.

Размещение индикаторов групп в заданном месте

Вы можете указать другое расположение индикаторов групп, например, справа. Для этого используются методы setIndicatorBounds() или setIndicatorBoundsRelative():

В примере использованы «магические числа». Вам лучше самостоятельно вычислить нужные значения.

Собственные индикаторы

Для создания собственных индикаторов приготовьте файлы *.9.png в двух состояниях (обычный и раскрытый) и пропишите их в drawable-ресурсах.

Пропишите селектор в атрибуте groupIndicator.

Источник

Полный список

— используем ListView для построения списка

Перед тем, как начать говорить про компонент ListView, предлагаю вспомнить еще раз прошлый урок и механизм построения списка, который мы там использовали. Мы перебирали массив данных, в каждой итерации создавали пункт списка, заполняли его данными и помещали в список.

При создании ListView создавать пункты за нас будет адаптер. Адаптеру нужны от нас данные и layout-ресурс пункта списка. Далее мы присваиваем адаптер списку ListView. Список при построении запрашивает у адаптера пункты, адаптер их создает (используя данные и layout) и возвращает списку. В итоге мы видим готовый список.

Есть различные типы списков и адаптеров. Мы пока что рассмотрим простейший вариант.

Project name: P0421_SimpleList
Build Target: Android 2.3.3
Application name: SimpleList
Package name: ru.startandroid.develop.p0421simplelist
Create Activity: MainActivity

Открываем main.xml и добавим на экран компонент ListView (вкладка Composite):

ListView – это и есть компонент списка.

Теперь надо создать адаптер. Открываем MainActivity.java и пишем:

Вы не поверите, но это весь код, необходимый для создания списка )

В качестве данных используем массив имен. В onCreate мы находим список, создаем адаптер и присваиваем адаптер списку. Давайте разберемся, как создали адаптер.

и передали ему следующие параметры:

this – контекст
android.R.layout.simple_list_item_1 – это системный layout-файл, который представляет собой TextView
names – массив данных, которые мы хотим вывести в список

Мы можем посмотреть содержимое использованного simple_list_item_1. Для этого в вашем проекте найдите пункт Android 2.3.3., раскройте его, и раскройте android.jar

Проматывайте в самый низ и открывайте res.layout.

И внутри находим используемый нами simple_list_item_1

Двойной клик на него и смотрим содержимое:

Обычный TextView с набором параметров.

Когда список при формировании запрашивает очередной пункт, адаптер берет этот Layout-ресурс simple_list_item_1, прогоняет его через LayoutInflater и получает View, преобразует View к TextView, присваивает ему текст из массива данных и отдает списку.

Все сохраним и запустим. Видим список из наших данных.

Использование системного layout-ресурса simple_list_item_1 хорошо тем, что нам не надо самим layout рисовать. Однако, если нас не устраивает то, как выглядит список с использованием simple_list_item_1 в качестве пункта списка, мы можем создать свой layout-ресурс.

Создадим layout-файл my_list_item.xml в папке res/layout нашего проекта:

TextView с указанием цвета и размера шрифта, выравнивания текста и отступов.

Изменим существующий код, укажем адаптеру наш созданный layout-ресурс my_list_item:

Теперь адаптер будет использовать его при создании пунктов списка.

Все сохраним и запустим. Видим наш зеленый список:

В layout-ресурсе для пункта списка вместо TextView вы можете использовать какой-нибудь его производный класс – например Button. Главное, чтобы объект прошел преобразование к TextView. Адаптер присвоит ему текст методом setText и отдаст списку.

Немного про Context

На одном из прошлых уроков я говорил, что Context (контекст) используется для доступа к базовым функциям приложения. В этом уроке у нас получилось хорошее подтверждение этим словам.

ArrаyAdapter использует LayoutInflater, чтобы конвертнуть layout-ресурс в View. Но получение объекта LayoutInflater – это одна из базовых функций и она недоступна для класса ArrаyAdapter. Поэтому мы в ArrаyAdapter в качестве контекста передаем ссылку на Activity (Activity имеет доступ к базовым функциям через восходящую иерархию классов). А класс ArrayAdapter внутри себя использует переданный ему контекст, чтобы вызвать LayoutInflater. Без контекста он не смог бы это сделать.

На следующем уроке:

— используем список ListView для одиночного и множественного выбора элементов

public ArrayAdapter (Context context, int textViewResourceId, T[] objects)

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Полный список

— строим список-дерево ExpandableListView

Если список элементов получается большой, имеет смысл разбить его на группы для упрощения навигации. Для этих целей можно использовать ExpandableListView. Это список в виде двухуровневого дерева. Первый уровень – группа, а в ней второй – элемент.

Чтобы построить такой список нам нужно как-то передать адаптеру данные по группам и элементам.

Каждая группа представляет из себя Map . Этот Map содержит атрибуты, которые вам нужны для каждой группы. Потом все эти Map (группы) собираются в List-коллекцию, например ArrayList. В итоге мы получили упакованные в один объект группы.

Каждый элемент группы также представлен объектом Map . Мы собираем все Map (элементы) для каждой группы в отдельную коллекцию. Получается, каждой группе соответствует коллекция с элементами. Далее эти коллекции мы теперь помещаем в общую коллекцию. Т.е. получается подобие двумерного массива. И в итоге пункты упакованы в один объект.

Сейчас начнем кодить пример и там станет понятнее.

List-коллекции называются обычно «список». Но т.к. список в контексте последних уроков — это набор пунктов на экране (ListView), то чтобы не путаться я буду использовать слово «коллекция».

Project name: P0451_ExpandableList
Build Target: Android 2.3.3
Application name: ExpandableList
Package name: ru.startandroid.develop.p0451expandablelist
Create Activity: MainActivity

Нарисуем экран main.xml:

Только ExpandableList на экране.

Код громоздкий и сложный, давайте разбираться.

Сначала мы в классе описываем массивы данных – это названия групп и названия элементов для них. Я решил в качестве данных выбрать смартфоны. Группы в нашем списке – это будут компании, а элементысмартфоны этих компаний.

Затем описываем коллекцию для групп, коллекции для элементов и Map для атрибутов.

В методе onCreate заполняем groupData. Это коллекция групп. Каждая группа представляет собой Map. А в Map мы пишем необходимые нам атрибуты для каждой группы. В нашем случае, для каждой группы мы укажем всего один атрибут groupName — это название компании из массива groups.

Как мы помним, адаптер обычно использует layout-ресурс для отображения пункта списка. В нашем случае пунктами ListView являются и группа и элемент. В layout-ресурсе могут быть какие-либо TextView. Мы можем заполнить их значениями из атрибутов элементов или групп, которые собраны в Map. Для этого нам надо указать сначала имена атрибутов, которые хотим использовать, а затем ID TextView-элементов, в которые хотим поместить значения этих атрибутов. Речь сейчас идет о текстовых атрибутах. (Хотя вообще атрибут вовсе не обязан быть класса String)

Для связки атрибутов и TextView-элементов мы используем два массива:

groupFrom – список имен атрибутов, которые будут считаны. В нашем случае – это groupName, который мы добавили к группе с помощью Map чуть выше в коде, когда собирали группы в groupData.
groupTo – список ID View-элементов, в которые будут помещены считанные значения атрибутов. Наш используемый layout будет содержать TextView с >

Два этих массива сопоставляются по порядку элементов. В итоге, в layout-ресурсе группы найдется элемент с и в него запишется текст из атрибута groupName. Тем самым мы получим отображение имени группы (компании) в списке.

Далее формируем коллекции элементов. Создаем общую коллекцию коллекций. А затем создаем коллекции элементов каждой группы. Принцип тот же, что и с группами – создаем Map и в него пишем атрибут phoneName со значением равным имени элемента (телефона). Коллекцию элементов для каждой группы добавляем в общую коллекцию.

Формируем два массива для сопоставления TextView из layout и атрибутов элементов. Полностью аналогично, как выше мы уже проделали с группами. В итоге при отображении элемента, найдется TextView с и туда запишется текст из атрибута phoneName. И мы увидим текст нашего элемента (телефона) в списке.

В конце кода мы создаем адаптер SimpleExpandableListAdapter и присваиваем его списку.

На вход при создании адаптера идут элементы:

this – контекст
groupData – коллекция групп
android.R.layout.simple_expandable_list_item_1 – layout-ресурс, который будет использован для отображения группы в списке. Соответственно, запросто можно использовать свой layout-файл.
groupFrom – массив имен атрибутов групп
groupTo – массив ID TextView из layout для групп
childData – коллекция коллекций элементов по группам
android.R.layout.simple_list_item_1 — layout-ресурс, который будет использован для отображения элемента в списке. Можно использовать свой layout-файл
childFrom – массив имен атрибутов элементов
childTo — массив ID TextView из layout для элементов.

В общем непростая, на мой взгляд, реализация дерева получилась. Возможно, не сразу получится понять. Но я попытался расписать все досконально и как можно подробнее.

Layout simple_expandable_list_item_1, который мы использовали для отображения групп – это TextView с отступом от левого края, чтобы осталось место для кнопки раскрытия/сворачивания списка. Для эксперимента вы можете попробовать использовать для групп layout simple_list_item_1, который мы использовали для элементов. В этом случае текст будет пересекаться с кнопкой.

А вообще вы можете создать для элементов свой layout, например, с тремя TextView. И к каждому элементу списка (Map) добавить еще по два атрибута: цена и цвет. Далее указываете ваш layout в конструкторе, формируете соответственно массивы childFrom и childTo чтобы сопоставить атрибуты и TextView, и получится, что каждый элемент группы содержит более подробную информацию о смартфоне.

На следующем уроке:

— обрабатываем события дерева-списка

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Читайте также:  Диспетчер устройств android google
Оцените статью