Listview的添加头部源码分析.基于Android 27
当我使用listView.addHeaderView(view);的时候.
public void addHeaderView(View v) {
//调用下面的代码
addHeaderView(v, null, true);
}
public void addHeaderView(View v, Object data, boolean isSelectable) {
final FixedViewInfo info = new FixedViewInfo();
//把头布局的View和数据封装到FixedViewInfo中
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
//把FixedViewInfo添加到集合中
mHeaderViewInfos.add(info);
mAreAllItemsSelectable &= isSelectable;
// Wrap the adapter if it wasn't already wrapped.
//如果mAdapter不为空
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();
}
}
}
/** @hide */
protected void wrapHeaderListAdapterInternal() {
//把mAdapter传值到wrapHeaderListAdapterInternal并赋值给mAdapter.
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
/** @hide */
protected HeaderViewListAdapter wrapHeaderListAdapterInternal(
ArrayList<ListView.FixedViewInfo> headerViewInfos,
ArrayList<ListView.FixedViewInfo> footerViewInfos,
ListAdapter adapter) {
//把HeaderView的集合,FooterView的集合和原来的Adapter作为参数传给HeaderViewListAdapter
//最终new HeaderViewListAdapter 对象进行返回.^_^以前的版本没有这么多调用的.
return new HeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter);
}
看到这里可以看出来.其实就是在原来的Adapter进行一层包装.下面分析HeaderViewListAdapter
Listview的Adapter最重要的几个方法:
getCount
public int getCount() {
if (mAdapter != null) {
//count的为头布局的条目加上底布局的条目加上原来Adapter的条目
return getFootersCount() + getHeadersCount() + mAdapter.getCount();
} else {
return getFootersCount() + getHeadersCount();
}
}
getView()
public View getView(int position, View convertView, ViewGroup parent) {
// Header (negative positions will throw an IndexOutOfBoundsException)
//如果当期的位置小于头布局的条目.直接取头布局的View
int numHeaders = getHeadersCount();
if (position < numHeaders) {
return mHeaderViewInfos.get(position).view;
}
// Adapter
//当前的position - 头布局的数量 ,让数量重新从0开始计算.
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getCount();
if (adjPosition < adapterCount) {
//从0开始计算的position.如果不从0开始,原来的Adapter的数据会发生错乱.
return mAdapter.getView(adjPosition, convertView, parent);
}
}
// Footer (off-limits positions will throw an IndexOutOfBoundsException)
//adjPosition - adapterCount 还是重新从0开始计算.从不然就发生角标越界异常.
return mFooterViewInfos.get(adjPosition - adapterCount).view;
}
看到这里.可以看出Listview原本是不支持添加头部布局.只是系统给我写好了.并做好了处理.让我们无感知而已.