Актовность ListActivity вместе со всем своим волшебством в большинстве случаев хорошо справляется с задачей представления списков меню:
Однако временами возникает потребность показать пользователю более информативный список, чем показан на картинке выше. В таком случае нужно немного модернизировать магию построения списка.
В нашем случае программа должна была в списке показывать не только название каждого элемента, но и дополнительную информацию, а также предоставлять пользователю без лишних телодвижений включить-выключить любой пункт меню посредством стандартного чекбокса. На экране все это колдунство выглядело приблезительно так:
Т.е. вместо стандартного текста каждый элемент этого кастомного меню содержит а) текстбокс для названия (большой шрифт), б) текстбокс для описания (мелкий щрифт) и ц) чекбокс для увлекательного чеканья.
В коде эта картинка звучит следующим образом:
public class MyAdapter extends ArrayAdapter<MyDataClass> { public MyAdapter(final Context context, final List<MyDataClass> items) { // Конструктор super(context, R.layout.sensorslist, items); } @Override public View getView(final int position, final View convertView, final ViewGroup parent) { // Инициализация пунктов меню, каждого в отдельности TextView title = (TextView) v.findViewById(R.id.sensor_text); TextView details = (TextView) v.findViewById(R.id.sensor_comments); CheckBox enabled = (CheckBox) v.findViewById(R.id.sensor_enabled); // И потом делаем с ними что хотим... } }NB. Метод getView вызывается автоматически классом-родителем при создании пунктов меню, причем вызывается для каждого пункта, а не для всего списка сразу.
В конструктор помимо контекста передается список с кастомным классом данных (о нем еще ниже будет). К созданному классу MyAdapter применяется свой лэйаут, который определяет расположение элементов внутри каждого пункта меню:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/sensor_text" android:layout_width="200dp" android:layout_height="wrap_content" android:lines="1" android:scrollHorizontally="true" android:ellipsize="end" android:paddingLeft="2sp" android:paddingTop="2sp" android:textSize="18sp" android:textStyle="bold" android:shadowColor="#90909090" android:shadowDx="1.0" android:shadowDy="1.0" android:shadowRadius="1.0"/> <TextView android:id="@+id/sensor_comments" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" android:textColor="#FF808080" android:paddingLeft="2sp" android:paddingTop="2sp"/> </LinearLayout> <CheckBox android:id="@+id/sensor_enabled" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_alignParentRight="true" android:paddingRight="5sp"/> </RelativeLayout>
И, наконец, вызывается все это волшебство в нужной активности с помощью нехитрых махинаций
public class ExtendedListActivity extends ListActivity { @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); List<MyDataClass> datas = new List<MyDataClass>(); // Здесь мы совершаем необходимые нам махинации с классами данных, // добавляя созданные инстансы в список for (int i = 0; i < 10; i++) { MyDataClass cl = new MyDataClass(); datas.add(cl) } MyAdapter adapter = new MyAdapter(this.getApplicationContext(), datas); setListAdapter(adapter); // А теперь создадим слушателя для тыков в меню ListView v = this.getListView(); v.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(final AdapterView<?> arg0, final View view, final int clicked, final long position) { // Получаем номер пункта меню и исполняем // свой танец } }); } }
Все, вроде, в порядке вещей, однако не слишком подкованные гипнотезеры часто упускают из вида один совсем неочевидный (к сожалению, довольно обычное дело для дядьки Андроида) момент, и в итоге это может приводить к непонятному хаосу в погоне за невидимым багом. Дело в том, что активность ListActivity, которая ответственна за показ элементов в виде списка, напрочь отказывается запускать OnItemClickListener (отросток, который помогает отлавливать события нажатий на пункты меню) ни за какие деньги. Принципиальная.
Чтобы нерадивые гипнотезеры и дальше паниковали под действием своего же хаоса, незаметно добавляем строчку в лэйаут, описывающий чекбокс:
<CheckBox android:id="@+id/sensor_enabled" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_alignParentRight="true" android:focusable="false" android:paddingRight="5sp"/>
И молча хихикаем в сторонке, зная, что Андроид не позволяет выбирать из списка айтемы, элементы которых могут быть фокусируемыми (focusable).