Android ListView 标头 [英] Android ListView headers
问题描述
我的 ListView 上有某种事件.事件按天排序,我希望每天都有带有日期的标题,然后在下面监听事件.
这是我填充该列表的方式:
ArrayListcrs = new ArrayList();crs.add(new TwoText("This will be header", event.getDate()));对于(事件事件:事件){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 {公共字符串类ID;公共字符串状态;public TwoText(字符串类ID,字符串状态){this.classID = classID;this.state = 状态;}}
这就是我的 TwoTextArrayAdapter 类的样子:
import java.util.ArrayList;导入 android.app.Activity;导入 android.content.Context;导入 android.view.LayoutInflater;导入 android.view.View;导入 android.view.ViewGroup;导入 android.widget.ArrayAdapter;导入 android.widget.TextView;公共类 TwoTextArrayAdapter 扩展了 ArrayAdapter{私有 ArrayList班级;私人活动骗局;文本视图分隔符;公共 TwoTextArrayAdapter(活动上下文,int textViewResourceId,ArrayList 类){超级(上下文,textViewResourceId,类);this.con = 上下文;this.classes = 类;}@覆盖public View getView(int position, View convertView, ViewGroup parent) {视图 v = 转换视图;如果(v == 空){LayoutInflater vi = (LayoutInflater) con.getSystemService(Context.LAYOUT_INFLATER_SERVICE);v = vi.inflate(R.layout.my_list_item, null);}TwoText user = classes.get(position);如果(用户!= null){TextView content1 = (TextView) v.findViewById(R.id.list_content1);TextView content2 = (TextView) v.findViewById(R.id.list_content2);如果(内容 1 != 空){content1.setText(user.classID);}if(content2 != null) {content2.setText(user.state);}}返回 v;}}
这是 my_list_item.xml
<文本视图style="?android:attr/listSeparatorTextViewStyle"android:id="@+id/分隔符"机器人:文本=标题"android:layout_width="fill_parent"android:layout_height="wrap_content"机器人:背景=#757678"android:textColor="#f5c227"/><线性布局xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"机器人:方向=水平"><文本视图android:id="@+id/list_content1"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_margin="5dip"机器人:可点击=假"机器人:重力=中心"机器人:longClickable =假"机器人:paddingBottom =1dip"android:paddingTop="1dip"机器人:文本=样本"android:textColor="#ff7f1d"android:textSize="17dip"android:textStyle="粗体"/><文本视图android:id="@+id/list_content2"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_margin="5dip"机器人:可点击=假"机器人:重力=中心"机器人:链接点击=假"机器人:longClickable =假"机器人:paddingBottom =1dip"android:paddingTop="1dip"机器人:文本=样本"android:textColor="#6d6d6d"android:textSize="17dip"/></LinearLayout></LinearLayout>
我目前所做的是将标题添加为常规列表对象,但我希望将其作为标题,并且在我的情况下有日期.
我的 xml 中有此代码用于标题:
我尝试在不需要时隐藏它并在需要时显示它,但我只是搞砸了我的其余代码.我尝试了更多教程,但它们也有相同的效果.
有人能指导我如何做这种简单的方法吗?
这是我的做法,关键是 getItemViewType 和 Adapter 类中的 rel="noreferrer">getViewTypeCount.getViewTypeCount
返回列表中有多少类型的项目,在本例中,我们有一个标题项目和一个事件项目,所以有两个.getItemViewType
应该返回我们在输入 position
处有什么类型的 View
.
Android 将负责在 convertView
中自动向您传递正确类型的 View
.
以下代码的结果如下所示:
首先我们有一个接口,我们的两个列表项类型将实现
公共接口项{公共 int getViewType();public View getView(LayoutInflater inflater, View convertView);}
然后我们有一个接受 Item
public class TwoTextArrayAdapter extends ArrayAdapter- {私人 LayoutInflater mInflater;公共枚举行类型 {LIST_ITEM、HEADER_ITEM}public TwoTextArrayAdapter(上下文上下文,列表<项目>项目){超级(上下文,0,项目);mInflater = LayoutInflater.from(context);}@覆盖公共 int getViewTypeCount() {返回 RowType.values().length;}@覆盖公共 int getItemViewType(int position) {返回 getItem(position).getViewType();}
<块引用>
@Overridepublic View getView(int position, View convertView, ViewGroup parent) {返回 getItem(position).getView(mInflater, convertView);}
编辑更好的性能..滚动时可以注意到
private static final int TYPE_ITEM = 0;私有静态最终 int TYPE_SEPARATOR = 1;public View getView(int position, View convertView, ViewGroup parent) {ViewHolder 持有人 = null;int rowType = getItemViewType(position);查看视图;if (convertView == null) {持有人 = 新的 ViewHolder();开关(行类型){案例 TYPE_ITEM:convertView = mInflater.inflate(R.layout.task_details_row, null);holder.View=getItem(position).getView(mInflater, convertView);休息;案例 TYPE_SEPARATOR:convertView = mInflater.inflate(R.layout.task_detail_header, null);holder.View=getItem(position).getView(mInflater, convertView);休息;}convertView.setTag(holder);}别的{持有人 = (ViewHolder) convertView.getTag();}返回转换视图;}公共静态类 ViewHolder {公共视图;}}
然后我们有类来实现Item
并扩展正确的布局.在您的情况下,您将拥有一个 Header
类和一个 ListItem
类.
public class Header 实现 Item {私有最终字符串名称;公共标题(字符串名称){this.name = 名称;}@覆盖公共 int getViewType() {返回 RowType.HEADER_ITEM.ordinal();}@覆盖公共视图 getView(LayoutInflater inflater, View convertView) {查看视图;if (convertView == null) {视图 = (视图) inflater.inflate(R.layout.header, null);//做一些初始化} 别的 {视图 = 转换视图;}TextView text = (TextView) view.findViewById(R.id.separator);text.setText(name);返回视图;}}
然后是 ListItem
类
公共类 ListItem 实现了 Item {私有最终字符串str1;私有最终字符串 str2;公共列表项(字符串文本1,字符串文本2){this.str1 = text1;this.str2 = text2;}@覆盖公共 int getViewType() {返回 RowType.LIST_ITEM.ordinal();}@覆盖公共视图 getView(LayoutInflater inflater, View convertView) {查看视图;if (convertView == null) {视图 = (视图) inflater.inflate(R.layout.my_list_item, null);//做一些初始化} 别的 {视图 = 转换视图;}TextView text1 = (TextView) view.findViewById(R.id.list_content1);TextView text2 = (TextView) view.findViewById(R.id.list_content2);text1.setText(str1);text2.setText(str2);返回视图;}}
还有一个简单的Activity
来显示它
public class MainActivity extends ListActivity {@覆盖protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);列表<项目>items = new ArrayList- ();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 适配器 = new TwoTextArrayAdapter(this, items);setListAdapter(适配器);}}
R.layout.header
<文本视图style="?android:attr/listSeparatorTextViewStyle"android:id="@+id/分隔符"机器人:文本=标题"android:layout_width="fill_parent"android:layout_height="wrap_content"机器人:背景=#757678"android:textColor="#f5c227"/></LinearLayout>
R.layout.my_list_item
的布局
<文本视图android:id="@+id/list_content1"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_margin="5dip"机器人:可点击=假"机器人:重力=中心"机器人:longClickable =假"机器人:paddingBottom =1dip"android:paddingTop="1dip"机器人:文本=样本"android:textColor="#ff7f1d"android:textSize="17dip"android:textStyle="粗体"/><文本视图android:id="@+id/list_content2"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_margin="5dip"机器人:可点击=假"机器人:重力=中心"机器人:链接点击=假"机器人:longClickable =假"机器人:paddingBottom =1dip"android:paddingTop="1dip"机器人:文本=样本"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"工具:context=".MainActivity" ><列表视图android:id="@android:id/列表"android:layout_width="fill_parent"android:layout_height="fill_parent"/></RelativeLayout>
你也可以变得更有趣,使用 ViewHolders
、异步加载内容或任何你喜欢的东西.
I have ListView that has some kind of events on it. Events are sorted by day, and I would like to have header with date on it for every day, and then events listen below.
Here is how I populate that list:
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);
and this is how my class TwoText looks:
public class TwoText {
public String classID;
public String state;
public TwoText(String classID, String state) {
this.classID = classID;
this.state = state;
}
}
and this is how my TwoTextArrayAdapter class looks:
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;
}
}
and this is 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>
what I do at the moment is that I am adding header just as regular list object, but Id like it to be as header and in my case have a date on it.
I have this code in my xml for header:
<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" />
and I tried hiding it when it is unneccessary and showing it when neccessary but I just messed up rest of my code. I tried few more tutorials but they also had same effect.
Could anyone guide me on how to do that easy way?
Here's how I do it, the keys are getItemViewType and getViewTypeCount in the Adapter
class. getViewTypeCount
returns how many types of items we have in the list, in this case we have a header item and an event item, so two. getItemViewType
should return what type of View
we have at the input position
.
Android will then take care of passing you the right type of View
in convertView
automatically.
Here what the result of the code below looks like:
First we have an interface that our two list item types will implement
public interface Item {
public int getViewType();
public View getView(LayoutInflater inflater, View convertView);
}
Then we have an adapter that takes a list of 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.. can be noticed when scrolling
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; }
}
Then we have classes the implement Item
and inflate the correct layouts. In your case you'll have something like a Header
class and a ListItem
class.
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;
}
}
And then the ListItem
class
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;
}
}
And a simple Activity
to display it
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);
}
}
Layout for 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>
Layout for 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>
Layout for 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>
You can also get fancier and use ViewHolders
, load stuff asynchronously, or whatever you like.
这篇关于Android ListView 标头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!