Как добавить несколько заголовков в один ListView с помощью addHeaderView()?
Можно ли использовать Android addHeaderView() для добавления нескольких заголовков в один список ListView? Может ли кто-нибудь дать пример того, как это сделать?
Я смог выполнить то, что хотел, манипулируя классом IconicAdapter... есть ли какая-то причина, почему я не должен этого делать? Я чувствую, что это может быть изменено для более продвинутых реализаций. В моем случае я знаю, что у меня будет два раздела с заголовком + 2 строки в каждом разделе.
class IconicAdapter extends ArrayAdapter<String> {
IconicAdapter() {
super(ContactTabProfileResource.this, R.layout.row_iconic, mArrayList);
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = getLayoutInflater();
View row = null;
if(position == 1 || position == 5) { // phone
row = inflater.inflate(R.layout.row_iconic, parent, false);
TextView label =(TextView)row.findViewById(R.id.label);
label.setText(mArrayList.get(position));
ImageView icon = (ImageView)row.findViewById(R.id.rowicon);
icon.setImageResource(R.drawable.icon_phone);
} else if (position == 2 || position == 6) { // email
row = inflater.inflate(R.layout.row_iconic, parent, false);
TextView label =(TextView)row.findViewById(R.id.label);
label.setText(mArrayList.get(position));
ImageView icon = (ImageView)row.findViewById(R.id.rowicon);
icon.setImageResource(R.drawable.icon_email);
} else if (position == 0 || position == 4) { // section header
row = inflater.inflate(R.layout.row_header, parent, false);
TextView label =(TextView)row.findViewById(R.id.label);
label.setText(mArrayList.get(position));
label.setBackgroundColor(Color.GRAY);
} else if (position == 3) { // section divider
row = inflater.inflate(R.layout.row_header, parent, false);
TextView label =(TextView)row.findViewById(R.id.label);
label.setText(" ");
}
return(row);
}
}
Затем я создал два разных XML-макета. row_header.xml для строк заголовка, а row_iconic.xml - для строк без заголовка, которые содержат значок.
row_header.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="right"
>
<TextView
android:id="@+id/label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingRight="10dp"
android:paddingLeft="10px"
android:gravity="left"
android:textStyle="bold"
/>
</LinearLayout>
row_iconic.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="right"
>
<TextView
android:id="@+id/label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingRight="10dp"
android:paddingLeft="44px"
/>
<ImageView
android:id="@+id/rowicon"
android:layout_width="40dp"
android:paddingRight="10dp"
android:paddingTop="10dp"
android:layout_height="30dp"
android:src="@drawable/icon"
/>
</LinearLayout>
Ответы
Ответ 1
Что вы хотите, чтобы разработчики Android могли вызвать разделитель списков или подзаголовок ( "заголовки" и "нижние колонтитулы" живут только в верхней или нижней части списка). Суть в том, как вы можете это сделать, - использовать ListAdapter, который обертывает другие ListAdapters и достаточно умен, чтобы возвращать тип заголовка для определенных строк и отслеживать смещения, или обертывает эти представления разделителей в их собственных мини-адаптерах.
Взгляните на Марка Мерфи SectionedListAdapter, GPL, который использует первый подход (на основе кода Джеффа Шарки) или его MergeAdapter и см. этот вопрос SO.
Это далеко от грациозной обработки подзаголовков смарт-списка на iPhone, но довольно просто использовать MergeAdapter и очень гибко, как только вы обернете свою голову вокруг того, что происходит внутри адаптеров.
Ответ 2
Если вы хотите вернуть разные макеты (например, элементы и заголовки), вы должны использовать getItemViewType(int position)
. Таким образом, ваш код адаптера должен выглядеть следующим образом:
private static final int TYPE_HEADER = 0;
private static final int TYPE_ICONIC = 1;
@Override
public int getViewTypeCount() {
return 2; // we have two types, so just return 2
}
@Override
public int getItemViewType(int position) {
// TODO: return TYPE_HEADER here if this position is a header, otherwise return TYPE_ICONIC
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO: return the appropriate layout
// hint: you might call getItemViewType(position) yourself here to know of which type the layout is
}
В принципе, как это работает. Чтобы гарантировать, что заголовки не могут быть выбраны, вы можете выбросить ArrayAdapter и использовать ListAdapter вместо этого, переопределив isEnabled(int position)
, чтобы вернуть false для ваших заголовков,; -)
Ответ 3
Вы можете добавить столько заголовков, сколько хотите, вызвав addHeaderView() несколько раз. Вы должны сделать это, прежде чем устанавливать адаптер в список.
Ответ 4
Вы также можете использовать этот класс в качестве примера. Он поддерживает "разделы" и "действия", где "разделы" представляют собой просто группы "действия" (элементы), они имеют не кликабельный и неизбираемый заголовок элемента. "Действия" могут указывать обработчик onClick
, который будет вызываться, когда это "действие" будет нажато, если оно существует. Он также содержит ImageLoader
для получения изображений для "действий" из Интернета.