Material Design RecyclerView添加头部底部布局(五)

本文介绍了一种在RecyclerView中添加头部和底部布局的方法,通过模仿ListView的实现方式,使用装饰者模式创建了一个自定义的WrapRecyclerView及适配器。

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

前言:相信很多人都知道,现在的日常开发中,已经逐渐由RecyclerView代替ListView、GridView,但相对于后者来说,RecyclerView存在着一些缺点,比如这篇文章要讲的,RecyclerView没有添加头部布局和底部布局的方法。

想到这里,我就想着那listview里面是怎么实现的呢?是不是可以去模仿Listview也写一个自己的RecyclerView,话不多说,直接开始

ListView源码分析:

	//添加存放头部View和底部view的集合
	private ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList();
	private ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList();
	//添加头部
	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;
		//如果mAdapter不为空,这个if的作用个人理解应该是在setAdapter后,用户假如再次添加头部布局,
		会将原先已经经历过一次包装的HeaderViewListAdapter再一次包装
        if (mAdapter != null) {
            if (!(mAdapter instanceof HeaderViewListAdapter)) {
				//如果此adapter没有被包装过,包装成具有HeaderView的adapter
                mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
            }
            if (mDataSetObserver != null) {
                mDataSetObserver.onChanged();
            }
        }
    }
	
	public void addFooterView(View v, Object data, boolean isSelectable) {
		//保存底部信息
        final FixedViewInfo info = new FixedViewInfo();
        info.view = v;
        info.data = data;
        info.isSelectable = isSelectable;
		//添加信息到底部集合
        mFooterViewInfos.add(info);
        mAreAllItemsSelectable &= isSelectable;
      	//如果mAdapter不为空,这个if的作用个人理解应该是在setAdapter后,用户假如再次添加底部布局,
		会将原先已经经历过一次包装的HeaderViewListAdapter再一次包装
        if (mAdapter != null) {
            if (!(mAdapter instanceof HeaderViewListAdapter)) {
				//如果此adapter没有被包装过,包装成具有FooterView的adapter
                mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
            }
            if (mDataSetObserver != null) {
                mDataSetObserver.onChanged();
            }
        }
    }
	
	@Override
	public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();
		//如果头部集合或者底部集合不为空,则将Activity编写的adapter带入到HeadViewListAdapter进行包装,否则还是用原来的adapter
        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }

        mOldSelectedPosition = INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;

        // AbsListView#setAdapter will update choice mode states.
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);

            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

            int position;
            if (mStackFromBottom) {
                position = lookForSelectablePosition(mItemCount - 1, false);
            } else {
                position = lookForSelectablePosition(0, true);
            }
            setSelectedPositionInt(position);
            setNextSelectedPositionInt(position);

            if (mItemCount == 0) {
                // Nothing selected
                checkSelectionChanged();
            }
        } else {
            mAreAllItemsSelectable = true;
            checkFocus();
            // Nothing selected
            checkSelectionChanged();
        }

        requestLayout();
    }
	
	
	
	HeaderViewListAdapter:
		//得到主体item、头部item、底部item总和
	    public int getCount() {
        if (mAdapter != null) {
            return getFootersCount() + getHeadersCount() + mAdapter.getCount();
        } else {
            return getFootersCount() + getHeadersCount();
        }
    }
	
	//根据不同条件返回主体、头部、底部View
	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();
            if (adjPosition < adapterCount) {
                return mAdapter.getView(adjPosition, convertView, parent);
            }
        }
        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).view;
    }

以上代码运用了强大的装饰者模式,装饰者模式实现的是从一个对象外部给对象添加功能,
相当于改变了对象的外观,装饰过的对象,从外部系统来看已经不再是原来的对象,而是经过一系列装饰器装饰过的对象。 
这里就是将自己的写的Adapter转换成了内部的HeadViewListAdapter。

这里我们知道了listview如何实现添加头部和底部布局的现在我们就来模仿listview做一个添加头部和底部布局的Recyclerview

WrapRecyclerView.java:

public class WrapRecyclerView extends RecyclerView{

    private ArrayList<View> mHeaderViewInfos = new ArrayList<View>();
    private ArrayList<View> mFooterViewInfos = new ArrayList<View>();
    private Adapter mAdapter;

    public WrapRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void addHeaderView(View v) {
        mHeaderViewInfos.add(v);
		
        // Wrap the adapter if it wasn't already wrapped.
        if (mAdapter != null) {
            if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {
                mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
            }

        }
    }

    public void addFooterView(View v) {
        mFooterViewInfos.add(v);
        // Wrap the adapter if it wasn't already wrapped.
        if (mAdapter != null) {
            if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {
                mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
            }
        }
    }


    @Override
    public void setAdapter(Adapter adapter) {

        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }
        super.setAdapter(mAdapter);
    }
}

HeaderViewRecyclerAdapter.java:

public class HeaderViewRecyclerAdapter extends RecyclerView.Adapter {

    private RecyclerView.Adapter mAdapter;
    ArrayList<View> mHeaderViewInfos;
    ArrayList<View> mFooterViewInfos;


    public HeaderViewRecyclerAdapter(ArrayList<View> headerViewInfos, ArrayList<View> footerViewInfos, RecyclerView.Adapter adapter) {
        mAdapter = adapter;
        if (headerViewInfos == null) {
            mHeaderViewInfos = new ArrayList<View>();
        } else {
            mHeaderViewInfos = headerViewInfos;
        }
        if (footerViewInfos == null) {
            mFooterViewInfos = new ArrayList<View>();
        } else {
            mFooterViewInfos = footerViewInfos;
        }

    }

    //判读当前条目是什么类型的--决定渲染什么视图
    @Override
    public int getItemViewType(int position) {
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {    //是头部
            return RecyclerView.INVALID_TYPE;
        }
        //正常条目部分
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemViewType(adjPosition);
            }
        }
        //footer部分
        return RecyclerView.INVALID_TYPE - 1;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //header
        if(viewType == RecyclerView.INVALID_TYPE){//头部
            return new HeadViewHolder(mHeaderViewInfos.get(0));
        }else if(viewType == RecyclerView.INVALID_TYPE-1){//尾部
            return new HeadViewHolder(mFooterViewInfos.get(0));
        }
        return mAdapter.onCreateViewHolder(parent,viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        //也要划分三个区域
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {    //是头部
           return;
        }
        //adapter body
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                mAdapter.onBindViewHolder(holder,adjPosition);
                return ;
            }
        }
        //footer部分

    }

    @Override
    public int getItemCount() {
        if (mAdapter != null) {
            return getFootersCount() + getHeadersCount() + mAdapter.getItemCount();
        } else {
            return getFootersCount() + getHeadersCount();
        }
    }

    public int getHeadersCount() {
        return mHeaderViewInfos.size();
    }

    public int getFootersCount() {
        return mFooterViewInfos.size();
    }

    private static class HeadViewHolder extends RecyclerView.ViewHolder{

        public HeadViewHolder(View itemView) {
            super(itemView);
        }
    }
}

MyAdapter.java:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private List<String> list;

    public MyAdapter(List<String> list) {
        this.list = list;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        View view = layoutInflater.inflate(R.layout.listitem, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.tv.setText(list.get(position));
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder{
        public TextView tv;


        public ViewHolder(View itemView) {
            super(itemView);
            tv = (TextView) itemView.findViewById(R.id.tv);
        }
    }
}

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        WrapRecyclerView recyclerView = (WrapRecyclerView) findViewById(R.id.recyclerview);


        //View headerView = View.inflate(this,resource,root);
        TextView headerView = new TextView(this);
        //TextView tv = headerView.findViewById(id);
        ActionBar.LayoutParams params = new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        headerView.setLayoutParams(params);
        headerView.setText("top");
        recyclerView.addHeaderView(headerView);

        TextView footview = new TextView(this);
        footview.setLayoutParams(params);
        footview.setText("bottom");
        recyclerView.addFooterView(footview);

        List<String> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            list.add("item"+i);
        }
        MyAdapter adapter = new MyAdapter(list);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
    }
}

这里相关的布局文件也很简单,这里就不贴代码了。

总结完毕。

不喜勿喷 谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值