Expandablelistview in android studio

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.

Источник

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

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

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

Создадим проект:

Project name: P0461_ExpandableListEvents
Build Target: Android 2.3.3
Application name: ExpandableListEvents
Package name: ru.startandroid.develop.p0461expandablelistevents
Create Activity: MainActivity

TextView для вывода информации и ExpandableListView.

В проекте, рядом с классом MainActivity создадим (не Activity) класс AdapterHelper. В него поместим код для заполнения списка, чтобы разгрузить MainActivity.java.

Код создания адаптера полностью заимствован с прошлого урока. Чтобы получить адаптер нам надо будет просто вызвать метод getAdapter.

У класса есть конструктор, через который мы передаем объекту ссылку на context. Context нам понадобится, чтобы создать адаптер. Адаптеру же в свою очередь context нужен, например, для доступа к LayoutInflater.

В конце класса находятся методы, которые возвращают нам названия групп и элементов из коллекций по номеру группы или номеру элемента. Для этого используем методы адаптера getGroup и getChild, приводим их к Map и извлекаем значение атрибута с именем компании или телефона.

Пишем код в MainActivity.java:

Благодаря классу AdapterHelper, код создания адаптера занял всего две строчки: создание объекта и вызов метода getAdapter. Далее присваиваем адаптер списку и добавляем обработчики:

Метод
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id), где

parent – ExpandableListView с которым работаем
v – View элемента
groupPosition – позиция группы в списке
childPosition – позиция элемента в группе
id – id элемента

Мы выводим в лог позицию и id. А в TextView сверху от списка выводим текст нажатого элемента и его группы, который получаем с помощью методов AdapterHelper.

Метод должен вернуть boolean. Если мы возвращаем true – это значит, мы сообщаем, что сами полностью обработали событие и оно не пойдет в дальнейшие обработчики (если они есть). Если возвращаем false – значит, мы позволяем событию идти дальше.

Метод
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id), где

parent – ExpandableListView с которым работаем
v – View элемента
groupPosition – позиция группы в списке
id – id группы

Мы выводим в лог позицию и id группы.

Этот метод также должен вернуть boolean. Мы будет возвращать true, если позиция группы = 1, иначе — false. Т.е. для этой группы мы блокируем дальнейшую обработку события. Далее увидим, что нам это даст.

Метод
onGroupCollapse(int groupPosition), где groupPosition – позиция группы, которую свернули

Метод
onGroupExpand(int groupPosition), где groupPosition – позиция группы, которую развернули

И в конце кода MainActivity мы разворачиваем группу с позицией 2, используя метод expandGroup.

Все сохраним и запускаем.

Как видим, группа LG сразу развернута. Это сработала команда expandGroup в конце кода.

Если посмотреть в лог, то видим

onGroupExpand groupPosition = 2

Т.е. отработало событие разворачивания группы с позицией 2.

Нажмем, например, на Optimus Link. Смотрим лог:

onChildClick groupPosition = 2 childPosition = 1 >

Не забываем, что позиция считается с нуля. Группа с позицией 2 – LG, элемент с позицией 1 – Optimus Link, все верно.

Смотрим TextView сверху экрана, он считал из адаптера значение атрибута и отобразил его.

Теперь попробуем свернуть группу LG, нажмем на нее. Смотрим лог:

onGroupClick groupPosition = 2 > onGroupCollapse groupPosition = 2

Сначала отработал onGroupClick – нажатие на группу, а потом onGroupCollapse – сворачивание группы. TextView наверху экрана оповестил о том, что свернули группу LG.

Снова развернем группу LG. Лог:

onGroupClick groupPosition = 2 > onGroupExpand groupPosition = 2

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

Теперь попробуем развернуть группу с позицией 1 – Samsung. Группа не разворачивается. Смотрим лог:

Событие нажатия есть, а вот обработчик разворачивания не вызывается. Это происходит из-за строчки

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

В итоге эти 4 обработчика позволяют вам определять, как пользователь взаимодействует с деревом.

Присоединяйтесь к нам в 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 для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Читайте также:  Симс для андроид одежда
Оцените статью