listView = (ListView) findViewById(R.id.test_lv);
headerView = LayoutInflater.from(this).inflate(R.layout.activity_position_test_headerview, null);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, datas);
listView.addHeaderView(headerView);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(ListViewPositionTestActivity.this, "Position is : " + i, Toast.LENGTH_SHORT).show();
}
});
如上述代码,给listView添加了一个headerView,运行出来之后的position如下图所示:
会发现数据的第一项position变成了1.
我们再来看一段代码:
listView = (ListView) findViewById(R.id.test_lv);
headerView = LayoutInflater.from(this).inflate(R.layout.activity_position_test_headerview, null);
headerView1 = LayoutInflater.from(this).inflate(R.layout.activity_position_test_headerview, null);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, datas);
listView.addHeaderView(headerView);
listView.addHeaderView(headerView1);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(ListViewPositionTestActivity.this, "Position is : " + i, Toast.LENGTH_SHORT).show();
}
});
会发现此时数据的第一项position变成了2.(由此也可以总结出,ListView是可以添加多个HeaderView的)
接下来我们分析分析,来看看addHeaderView(View view)的源码:
/**
* Add a fixed view to appear at the top of the list. If this method is
* called more than once, the views will appear in the order they were
* added. Views added using this call can take focus if they want.
* <p>
* Note: When first introduced, this method could only be called before
* setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
* {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
* called at any time. If the ListView's adapter does not extend
* {@link HeaderViewListAdapter}, it will be wrapped with a supporting
* instance of {@link WrapperListAdapter}.
*
* @param v The view to add.
* @param data Data to associate with this view
* @param isSelectable whether the item is selectable
*/
public void addHeaderView(View v, Object data, boolean isSelectable) {
final FixedViewInfo info = new FixedViewInfo();
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
mHeaderViewInfos.add(info);
mAreAllItemsSelectable &= isSelectable;
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewListAdapter)) {
wrapHeaderListAdapterInternal();
}
// In the case of re-adding a header view, or adding one later on,
// we need to notify the observer.
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
}
当mAdapter不为空时,执行wrapHeaderListAdapterInternal()方法,我们来接着看看源码:
/** @hide */
protected HeaderViewListAdapter wrapHeaderListAdapterInternal(
ArrayList<ListView.FixedViewInfo> headerViewInfos,
ArrayList<ListView.FixedViewInfo> footerViewInfos,
ListAdapter adapter) {
return new HeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter);
}
/** @hide */
protected void wrapHeaderListAdapterInternal() {
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
可以看到,mAdapter变成了HeaderViewListAdapter的对象,那么HeaderViewListAdapter又是什么呢?
public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos,
ArrayList<ListView.FixedViewInfo> footerViewInfos,
ListAdapter adapter) {
mAdapter = adapter;
mIsFilterable = adapter instanceof Filterable;
if (headerViewInfos == null) {
mHeaderViewInfos = EMPTY_INFO_LIST;
} else {
mHeaderViewInfos = headerViewInfos;
}
if (footerViewInfos == null) {
mFooterViewInfos = EMPTY_INFO_LIST;
} else {
mFooterViewInfos = footerViewInfos;
}
mAreAllFixedViewsSelectable =
areAllListInfosSelectable(mHeaderViewInfos)
&& areAllListInfosSelectable(mFooterViewInfos);
}
上面的HeaderViewListAdapter的构造方法,将headerViewInfos、footerViewInfos和之前的adapter传了进来,接下来我们看看这个类中的getCount()方法:
public int getCount() {
if (mAdapter != null) {
return getFootersCount() + getHeadersCount() + mAdapter.getCount();
} else {
return getFootersCount() + getHeadersCount();
}
}
public int getHeadersCount() {
return mHeaderViewInfos.size();
}
public int getFootersCount() {
return mFooterViewInfos.size();
}
发现了什么?上面的mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter);
方法返回的mAdapter的getCount()是 原先adapter的getCount() 和 HeaderView的总数 、FooterView的总数 之和!
这也就解释了为什么上面的两张图的position错位的原因。同理FooterView也是要占据position的值哦~
这里有几点要注意:
1. addHeaderView(View v, Object data, boolean isSelectable) 中有一个参数isSelectable,当这个值设置为true的时候,该HeaderView不能点击,点击无反应。FooterView同理。
2. 看addHeaderView(View v, Object data, boolean isSelectable)方法的注释,你会发现,在Android4.3(即KITKAT,API 19)之前,addHeaderView方法必须在setAdapter方法之前调用,而在API 19之后,addHeaderView方法可以在任何时间调用。所以在项目中要注意这一点。