Освой программирование играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Компонент ExpandableListView является расширенным вариантом компонента ListView. Основное отличие - разворачивающий список второго уровня. Получается список в списке. Рассмотрим простейший вариант:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ExpandableListView
android:id="@+id/expListView"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ExpandableListView>
</LinearLayout>
Сам по себе компонент не представляет интереса. Его необходимо заполнить данными. Переключимся в код активности и напишем следующее:
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.testapplication;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.SimpleExpandableListAdapter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends ActionBarActivity {
private String[] mGroupsArray = new String[] { "Зима", "Весна", "Лето", "Осень" };
private String[] mWinterMonthsArray = new String[] { "Декабрь", "Январь", "Февраль" };
private String[] mSpringMonthsArray = new String[] { "Март", "Апрель", "Май" };
private String[] mSummerMonthsArray = new String[] { "Июнь", "Июль", "Август" };
private String[] mAutumnMonthsArray = new String[] { "Сентябрь", "Октябрь", "Ноябрь" };
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("Locale Date");
Map<String, String> map;
// коллекция для групп
ArrayList<Map<String, String>> groupDataList = new ArrayList<>();
// заполняем коллекцию групп из массива с названиями групп
for (String group : mGroupsArray) {
// заполняем список атрибутов для каждой группы
map = new HashMap<>();
map.put("groupName", group); // время года
groupDataList.add(map);
}
// список атрибутов групп для чтения
String groupFrom[] = new String[] { "groupName" };
// список ID view-элементов, в которые будет помещены атрибуты групп
int groupTo[] = new int[] { android.R.id.text1 };
// создаем общую коллекцию для коллекций элементов
ArrayList<ArrayList<Map<String, String>>> сhildDataList = new ArrayList<>();
// в итоге получится сhildDataList = ArrayList<сhildDataItemList>
// создаем коллекцию элементов для первой группы
ArrayList<Map<String, String>> сhildDataItemList = new ArrayList<>();
// заполняем список атрибутов для каждого элемента
for (String month : mWinterMonthsArray) {
map = new HashMap<>();
map.put("monthName", month); // название месяца
сhildDataItemList.add(map);
}
// добавляем в коллекцию коллекций
сhildDataList.add(сhildDataItemList);
// создаем коллекцию элементов для второй группы
сhildDataItemList = new ArrayList<>();
for (String month : mSpringMonthsArray) {
map = new HashMap<>();
map.put("monthName", month);
сhildDataItemList.add(map);
}
сhildDataList.add(сhildDataItemList);
// создаем коллекцию элементов для третьей группы
сhildDataItemList = new ArrayList<>();
for (String month : mSummerMonthsArray) {
map = new HashMap<>();
map.put("monthName", month);
сhildDataItemList.add(map);
}
сhildDataList.add(сhildDataItemList);
// создаем коллекцию элементов для четвертой группы
сhildDataItemList = new ArrayList<>();
for (String month : mAutumnMonthsArray) {
map = new HashMap<>();
map.put("monthName", month);
сhildDataItemList.add(map);
}
сhildDataList.add(сhildDataItemList);
// список атрибутов элементов для чтения
String childFrom[] = new String[] { "monthName" };
// список ID view-элементов, в которые будет помещены атрибуты
// элементов
int childTo[] = new int[] { android.R.id.text1 };
SimpleExpandableListAdapter adapter = new SimpleExpandableListAdapter(
this, groupDataList,
android.R.layout.simple_expandable_list_item_1, groupFrom,
groupTo, сhildDataList, android.R.layout.simple_list_item_1,
childFrom, childTo);
ExpandableListView expandableListView = (ExpandableListView) findViewById(R.id.expListView);
expandableListView.setAdapter(adapter);
}
}
Сначала мы описываем массивы данных – это названия групп (Времена года) и названия элементов для них (месяцы).
Затем описываем коллекцию для групп, коллекции для элементов и Map для атрибутов.
В методе onCreate() заполняем groupData. Это коллекция групп. Каждая группа представляет собой Map. А в Map мы пишем необходимые нам атрибуты для каждой группы. В нашем случае, для каждой группы мы укажем всего один атрибут groupName - это название из массива groups.
Адаптер обычно использует layout-ресурс для отображения пункта списка. В нашем случае пунктами ExpandableListView являются и группа и элемент. В layout-ресурсе могут быть какие-либо TextView. Мы можем заполнить их значениями из атрибутов элементов или групп, которые собраны в Map. Для этого нам надо указать сначала имена атрибутов, которые хотим использовать, а затем идентификаторы TextView, в которые хотим поместить значения этих атрибутов.
Для связки атрибутов и TextView мы используем два массива:
Два этих массива сопоставляются по порядку элементов. В итоге, в layout-ресурсе группы найдется элемент с ID = android.R.id.text1 и в него запишется текст из атрибута groupName. Тем самым мы получим отображение имени группы в списке.
Далее формируем коллекции элементов. Создаем общую коллекцию коллекций. А затем создаем коллекции элементов каждой группы. Принцип тот же, что и с группами – создаем Map и в него пишем атрибут monthName со значением равным имени элемента. Коллекцию элементов для каждой группы добавляем в общую коллекцию.
Формируем два массива для сопоставления TextView из layout и атрибутов элементов. Полностью аналогично, как выше мы уже проделали с группами. В итоге при отображении элемента, найдется TextView с ID = android.R.id.text1 и туда запишется текст из атрибута monthName. И мы увидим текст нашего элемента (месяца) в списке.
В конце кода создаем адаптер SimpleExpandableListAdapter и присваиваем его списку.
Параметры для адаптера:
Layout simple_expandable_list_item_1, который мы использовали для отображения групп – это TextView с отступом от левого края, чтобы осталось место для кнопки раскрытия/сворачивания списка. Для эксперимента вы можете попробовать использовать для групп layout simple_list_item_1, который мы использовали для элементов. В этом случае текст будет пересекаться с кнопкой.
А вообще вы можете создать для элементов свою разметку, например, с тремя TextView. И к каждому элементу списка (Map) добавить еще по два атрибута. Далее указываете вашу разметку в конструкторе, формируете соответственно массивы childFrom и childTo чтобы сопоставить атрибуты и TextView, и получится, что каждый элемент группы содержит более подробную информацию.
ExpandableListView редко используется в составе разметки с другими элементами. Обычно такой список занимает весь экран, поэтому для подобных целей лучше использовать специальный класс ExpandableListViewActivity, который уже содержит в своём составе компонент ExpandableListView.
Вы можете указать другое расположение индикаторов групп, например, справа. Для этого используются методы setIndicatorBounds() или setIndicatorBoundsRelative():
ExpandableListView expandableListView = (ExpandableListView) findViewById(R.id.expListView);
expandableListView.setAdapter(adapter);
if (android.os.Build.VERSION.SDK_INT <
android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
expandableListView.setIndicatorBounds(170, 200);
} else {
expandableListView.setIndicatorBoundsRelative(170, 200);
}
В примере использованы "магические числа". Вам лучше самостоятельно вычислить нужные значения.
Для создания собственных индикаторов приготовьте файлы *.9.png в двух состояниях (обычный и раскрытый) и пропишите их в drawable-ресурсах.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_expanded="true" android:drawable="@drawable/group_indicator_expanded" />
<item android:drawable="@drawable/group_indicator" />
</selector>
Пропишите селектор в атрибуте groupIndicator.
<ExpandableListView
android:id="@+id/expandableListView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:groupIndicator="@drawable/group_indicator_selector" >
</ExpandableListView>
Фильтруем базар. Поиск по тексту (ExpandableListView, SearchView) (Часть 3) (закрытая зона/3-й курс)
Кастомный ExpandableListView в Android