Android ListView标题

我有ListView上有一些事件。 事件按datesorting,我想每天都有标题和date,然后事件在下面进行监听。

以下是我如何填充该列表:

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> 

我现在所做的就是像正常的列表对象一样添加头文件,但是我喜欢将它作为头文件,在我的情况下有一个date。

我有这个代码在我的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" /> 

我试图隐藏它,当它是必要的,并显示需要时,但我只是搞砸了我的代码的其余部分。 我尝试了更多的教程,但他们也有同样的效果。

任何人都可以指导我如何做这个简单的方法吗?

以下是我如何做的,关键字是Adapter类中的getItemViewType和getViewTypeCount 。 getViewTypeCount返回列表中有多less种types的项目,在这种情况下,我们有一个标题项目和一个事件项目,所以有两个。 getItemViewType应该返回inputpositionViewtypes。

然后,Android会自动将您正确types的View传递给convertView

这里代码的结果如下所示: 例

首先我们有一个我们的两个列表项types将实现的接口

 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); } 

编辑 更好的性能..滚动时可以注意到

 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; } } 

和一个简单的Activity来显示它

 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 ,asynchronous加载东西,或者任何你喜欢的东西。

您可能正在寻找具有标题(组)来分隔项目(孩子)的ExpandableListView 。

关于这个问题的好教程: 在这里 。

作为一种替代scheme,为这个用例devise了一个很好的第三方库 。 因此您需要根据存储在适配器中的数据生成标题。 它们被称为Rolodex适配器,并与ExpandableListViews一起使用。 他们可以很容易地进行自定义,像标题一样的正常列表。

使用OP的Event对象并且知道标题是基于与其关联的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(例如2016年12月1日)作为标题。 我使用了StickyHeaderListView库

https://github.com/emilsjolander/StickyListHeaders

将date转换为以毫秒为单位的[不包括时间],并将其作为标题Id。

 @Override public long getHeaderId(int position) { return <date in millis>; }