Android ListView заголовки

У меня есть ListView, на котором есть какие-то события. События сортируются по дням, и я хотел бы иметь заголовок с датой на нем на каждый день, а затем события прослушивают ниже.

Вот как я заполняю этот список:

ArrayList<TwoText> crs = new ArrayList<TwoText>(); crs.add(new TwoText("This will be header", event.getDate())); for (Event event : events) { crs.add(new TwoText(event.getStartString() + "-" + event.getEndString(), event.getSubject())); } arrayAdapter = new TwoTextArrayAdapter(this, R.layout.my_list_item, crs); lv1.setAdapter(arrayAdapter); 

И так выглядит мой класс TwoText:

 public class TwoText { public String classID; public String state; public TwoText(String classID, String state) { this.classID = classID; this.state = state; } } 

И вот так выглядит мой класс TwoTextArrayAdapter:

 import java.util.ArrayList; import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; public class TwoTextArrayAdapter extends ArrayAdapter<TwoText> { private ArrayList<TwoText> classes; private Activity con; TextView seperator; public TwoTextArrayAdapter(Activity context, int textViewResourceId, ArrayList<TwoText> classes) { super(context, textViewResourceId, classes); this.con = context; this.classes = classes; } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater) con.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.my_list_item, null); } TwoText user = classes.get(position); if (user != null) { TextView content1 = (TextView) v.findViewById(R.id.list_content1); TextView content2 = (TextView) v.findViewById(R.id.list_content2); if (content1 != null) { content1.setText(user.classID); } if(content2 != null) { content2.setText(user.state); } } return v; } } 

И это my_list_item.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView style="?android:attr/listSeparatorTextViewStyle" android:id="@+id/separator" android:text="Header" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#757678" android:textColor="#f5c227" /> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/list_content1" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_margin="5dip" android:clickable="false" android:gravity="center" android:longClickable="false" android:paddingBottom="1dip" android:paddingTop="1dip" android:text="sample" android:textColor="#ff7f1d" android:textSize="17dip" android:textStyle="bold" /> <TextView android:id="@+id/list_content2" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_margin="5dip" android:clickable="false" android:gravity="center" android:linksClickable="false" android:longClickable="false" android:paddingBottom="1dip" android:paddingTop="1dip" android:text="sample" android:textColor="#6d6d6d" android:textSize="17dip" /> </LinearLayout> </LinearLayout> 

То, что я делаю в данный момент, заключается в том, что я добавляю заголовок как обычный объект списка, но Id нравится ему как заголовок и в моем случае имеет дату на нем.

У меня этот код в моем заголовке xml:

 <TextView style="?android:attr/listSeparatorTextViewStyle" android:id="@+id/separator" android:text="Header" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#757678" android:textColor="#f5c227" /> 

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

Может ли кто-нибудь помочь мне в том, как сделать этот простой способ?

Вот как я это делаю, ключи – getItemViewType и getViewTypeCount в классе Adapter . getViewTypeCount возвращает количество типов элементов, которые у нас есть в списке, в этом случае у нас есть элемент заголовка и элемент события, поэтому два. getItemViewType должен возвращать тип View мы видим во входной position .

Затем Android позаботится о том, чтобы передать вам правильный вид View в convertView автоматически.

Вот как выглядит результат кода ниже: пример

Сначала у нас есть интерфейс, который реализует наши два типа элементов списка.

 public interface Item { public int getViewType(); public View getView(LayoutInflater inflater, View convertView); } 

Тогда у нас есть адаптер, который берет список Item

 public class TwoTextArrayAdapter extends ArrayAdapter<Item> { private LayoutInflater mInflater; public enum RowType { LIST_ITEM, HEADER_ITEM } public TwoTextArrayAdapter(Context context, List<Item> items) { super(context, 0, items); mInflater = LayoutInflater.from(context); } @Override public int getViewTypeCount() { return RowType.values().length; } @Override public int getItemViewType(int position) { return getItem(position).getViewType(); } 
  @Override public View getView(int position, View convertView, ViewGroup parent) { return getItem(position).getView(mInflater, convertView); } 

EDIT Better For Performance .. можно заметить при прокрутке

 private static final int TYPE_ITEM = 0; private static final int TYPE_SEPARATOR = 1; public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; int rowType = getItemViewType(position); View View; if (convertView == null) { holder = new ViewHolder(); switch (rowType) { case TYPE_ITEM: convertView = mInflater.inflate(R.layout.task_details_row, null); holder.View=getItem(position).getView(mInflater, convertView); break; case TYPE_SEPARATOR: convertView = mInflater.inflate(R.layout.task_detail_header, null); holder.View=getItem(position).getView(mInflater, convertView); break; } convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } return convertView; } public static class ViewHolder { public View View; } } 

Затем у нас есть классы Item и раздуваются правильные макеты. В вашем случае у вас будет что-то вроде класса Header класса ListItem .

  public class Header implements Item { private final String name; public Header(String name) { this.name = name; } @Override public int getViewType() { return RowType.HEADER_ITEM.ordinal(); } @Override public View getView(LayoutInflater inflater, View convertView) { View view; if (convertView == null) { view = (View) inflater.inflate(R.layout.header, null); // Do some initialization } else { view = convertView; } TextView text = (TextView) view.findViewById(R.id.separator); text.setText(name); return view; } } 

Затем класс ListItem

  public class ListItem implements Item { private final String str1; private final String str2; public ListItem(String text1, String text2) { this.str1 = text1; this.str2 = text2; } @Override public int getViewType() { return RowType.LIST_ITEM.ordinal(); } @Override public View getView(LayoutInflater inflater, View convertView) { View view; if (convertView == null) { view = (View) inflater.inflate(R.layout.my_list_item, null); // Do some initialization } else { view = convertView; } TextView text1 = (TextView) view.findViewById(R.id.list_content1); TextView text2 = (TextView) view.findViewById(R.id.list_content2); text1.setText(str1); text2.setText(str2); return view; } } 

Простое действие для его отображения

 public class MainActivity extends ListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); List<Item> items = new ArrayList<Item>(); items.add(new Header("Header 1")); items.add(new ListItem("Text 1", "Rabble rabble")); items.add(new ListItem("Text 2", "Rabble rabble")); items.add(new ListItem("Text 3", "Rabble rabble")); items.add(new ListItem("Text 4", "Rabble rabble")); items.add(new Header("Header 2")); items.add(new ListItem("Text 5", "Rabble rabble")); items.add(new ListItem("Text 6", "Rabble rabble")); items.add(new ListItem("Text 7", "Rabble rabble")); items.add(new ListItem("Text 8", "Rabble rabble")); TwoTextArrayAdapter adapter = new TwoTextArrayAdapter(this, items); setListAdapter(adapter); } } 

Макет для R.layout.header

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView style="?android:attr/listSeparatorTextViewStyle" android:id="@+id/separator" android:text="Header" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#757678" android:textColor="#f5c227" /> </LinearLayout> 

Макет для R.layout.my_list_item

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/list_content1" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_margin="5dip" android:clickable="false" android:gravity="center" android:longClickable="false" android:paddingBottom="1dip" android:paddingTop="1dip" android:text="sample" android:textColor="#ff7f1d" android:textSize="17dip" android:textStyle="bold" /> <TextView android:id="@+id/list_content2" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_margin="5dip" android:clickable="false" android:gravity="center" android:linksClickable="false" android:longClickable="false" android:paddingBottom="1dip" android:paddingTop="1dip" android:text="sample" android:textColor="#6d6d6d" android:textSize="17dip" /> </LinearLayout> 

Макет для R.layout.activity_main.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </RelativeLayout> 

Вы также можете стать ViewHolders и использовать ViewHolders , загружать ViewHolders асинхронно или что угодно.

Вероятно, вы ищете ExpandableListView, у которого есть заголовки (группы) для разделения элементов (дочерние элементы).

Хороший учебник по теме: здесь .

В качестве альтернативы, есть хорошая сторонняя библиотека, предназначенная только для этого варианта использования. В связи с этим вам необходимо создать заголовки на основе данных, хранящихся в адаптере. Они называются адаптерами Rolodex и используются с ExpandableListViews . Их можно легко настроить, чтобы вести себя как обычный список с заголовками.

Использование объектов Event OP и знание заголовков основаны на связанной с ним Date … код будет выглядеть примерно так:

Активность

  //There's no need to pre-compute what the headers are. Just pass in your List of objects. EventDateAdapter adapter = new EventDateAdapter(this, mEvents); mExpandableListView.setAdapter(adapter); 

Адаптер

 private class EventDateAdapter extends NFRolodexArrayAdapter<Date, Event> { public EventDateAdapter(Context activity, Collection<Event> items) { super(activity, items); } @Override public Date createGroupFor(Event childItem) { //This is how the adapter determines what the headers are and what child items belong to it return (Date) childItem.getDate().clone(); } @Override public View getChildView(LayoutInflater inflater, int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { //Inflate your view //Gets the Event data for this view Event event = getChild(groupPosition, childPosition); //Fill view with event data } @Override public View getGroupView(LayoutInflater inflater, int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { //Inflate your header view //Gets the Date for this view Date date = getGroup(groupPosition); //Fill view with date data } @Override public boolean hasAutoExpandingGroups() { //This forces our group views (headers) to always render expanded. //Even attempting to programmatically collapse a group will not work. return true; } @Override public boolean isGroupSelectable(int groupPosition) { //This prevents a user from seeing any touch feedback when a group (header) is clicked. return false; } } 

Что я сделал, чтобы сделать Date (например, 01 декабря 2016 года) в качестве заголовка. Я использовал библиотеку StickyHeaderListView

https://github.com/emilsjolander/StickyListHeaders

Преобразуйте дату в миллисекунду [не включайте время] и сделайте ее как идентификатор заголовка.

 @Override public long getHeaderId(int position) { return <date in millis>; } 
Intereting Posts
Android Gradle Exception: «Несколько файлов dex определяют», дублированные классы под взрывом-aar APV PDF Reader. Проблемы с установкой, распаковкой и оригинальной библиотекой Офлайн-голосовое распознавание андроида с нежелательным голосом Мое приложение работает на android 2.3.3 для android 3.1, но останавливается с ошибкой на 4.0 + Доступ к переменной осуществляется внутри внутреннего класса. Необходимо объявить окончательным Как получить смещение прокрутки на MPAndroidChart? Как предотвратить вставлять дублирующее значение в базу данных sqlite (если дублировать, а затем перезаписать) GetHostAddress () возвращает обратный ip-адрес Обнаружение за VPN в Android Как использовать Dialog внутри BaseAdapter? Захват экрана для Android с appium Используя HttpURLConnection и HttpsURLConnection для подключения к https? Android – выбор текста из EditText Создание проекта с помощью Ant, который включает ActionbarSherlock в качестве проекта библиотеки Builg.gradle: как выполнять код только по выбранному вкусу