ListView源码分析之添加HeaderView(或FooterView)实现原理

本文探讨了RecyclerView缺少像ListView的addHeaderView()和addFooterView()功能的问题,并深入分析了ListView实现这一功能的源码,旨在帮助开发者了解如何在RecyclerView中自定义添加头部或尾部视图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先,RecyclerView 功能虽然强大但是没有像ListView的addHaderView()或者addFooterView之类的方法,但是我们实际开发中可能需要这么去做,必须我们自己去实现,为了给RecyclerView添加header 或者footer 我们今天来分析ListView是如何实现此功能的。

一、我们直接来看ListView.addHeaderView()方法,重点就是我们的adapter.

 public void addHeaderView(View v, Object data, boolean isSelectable) {
		//可以看到ListView把我们的HeaderView封装成了对象FixedViewInfo 存在了集合当中
		//private ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList();
		//private ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList();
		//说明可以添加多个headerView 和 footerView
		//
		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) {
		   // 如果设置的adapter不是HeaderViewListAdapter 就创建一个HeaderViewListAdapter 并把mAdapter传进去
		   // 这里就是说如果 添加有headerView或者footerView 就是用HeaderViewListAdapter来装饰我们的adapter
		   // 装饰模式
		    if (!(mAdapter instanceof HeaderViewListAdapter)) {
			mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
		    }

		    // 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();
		    }
		}
	    }
二、继续来看ListView.setAdapter()方法

    @Override
    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();
	 ////这里和 addHeaderView方法一样装饰了我们的adapter
        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }

       ........................

        requestLayout();
    }
三、上面我们看到了 HeaderViewListAdapter来装饰我们自己的adapter 我们这里就来看一下 HeaderViewListAdapter
public class HeaderViewListAdapter implements WrapperListAdapter, Filterable {

    private final ListAdapter mAdapter;
再看WraperListAdapter:

public interface WrapperListAdapter extends ListAdapter {
    /**
     * Returns the adapter wrapped by this list adapter.
     *
     * @return The {@link android.widget.ListAdapter} wrapped by this adapter.
     */
    public ListAdapter getWrappedAdapter();
}
可以看到 HeaderViewListAdapter 和我们自己的传进来的Adapter 都实现了ListAdapter接口,


这和我们普通的adapter没有什么大的区别 都拥有常用的方法 比如:getView()、getItem()、getCount()、getItemId()等
继续看getView()方法:

    //重点看这里:
    public View getView(int position, View convertView, ViewGroup parent) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return mHeaderViewInfos.get(position).view;
        }

        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getCount();
	    // 代理(做一个切面的编程):根据不同的position返回不同的view
            if (adjPosition < adapterCount) {
                return mAdapter.getView(adjPosition, convertView, parent);
            }
        }

        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).view;
    }
看到这里我想大家都明白了,getCount(),getItem()也是同样如此:
  public int getCount() {
        if (mAdapter != null) {
            return getFootersCount() + getHeadersCount() + mAdapter.getCount();
        } else {
            return getFootersCount() + getHeadersCount();
        }
    }
getItemId()方法:

 public long getItemId(int position) {
        int numHeaders = getHeadersCount();
        if (mAdapter != null && position >= numHeaders) {
            int adjPosition = position - numHeaders;
            int adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemId(adjPosition);
            }
        }
        return -1;
    }
看到这里我们了解了 ListView添加HeaderView 和 FooterView的实现原理,可以为RecyclerView添加简单的HeaderView 或者FooterView了。每天学一点,加油!





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值