android recyclerview添加头部,Android中封装RecyclerView实现添加头部和底部示例代码

前言

我们大家都知道ListView具有添加头部和添加底部的方法,但是RecyclerView并没有这样子的方法。所以RecyclerView是不能添加底部和头部的,但是能不能仿造ListView来实现RecyclerView添加头部和底部呢?答案当然是可行的。本文就来给大家介绍了关于Android封装RecyclerView添加头部和底部的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

首先看下实现的效果:

fccc0bbe4c30b41194fb0269befa0ec0.png

代码如下:

public class WrapMyRecyclerView extends RecyclerView {

private Adapter mAdapter;

private ArrayList mHeaderViewInfos = new ArrayList<>();//保存headerView

private ArrayList mFooterViewInfos = new ArrayList<>();//保存footerView

public WrapMyRecyclerView(Context context) {

super(context);

}

public WrapMyRecyclerView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

}

public WrapMyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

/**

* 添加headerView

* @param v

*/

public void addHeaderView(View v) {

mHeaderViewInfos.add(v);

// Wrap the adapter if it wasn't already wrapped.

if (mAdapter != null) {

if (!(mAdapter instanceof RecyclerHeaderViewListAdapter)) {

wrapHeaderListAdapterInternal();

}

}

}

/**

* 添加一个footerView

* @param v

*/

public void addFooterView(View v) {

mFooterViewInfos.add(v);

// Wrap the adapter if it wasn't already wrapped.

if (mAdapter != null) {

if (!(mAdapter instanceof RecyclerHeaderViewListAdapter)) {

wrapHeaderListAdapterInternal();

}

}

}

/**

* 设置一个Adapter

* @param adapter

*/

@Override

public void setAdapter(Adapter adapter) {

if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {

mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);

} else {

mAdapter = adapter;

}

super.setAdapter(mAdapter);

}

private void wrapHeaderListAdapterInternal() {

mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter);

}

/**

* 新建一个RecyclerHeaderViewListAdapter对象

* 最终的adapter实现它

* @param headerViewInfos

* @param footerViewInfos

* @param adapter

* @return

*/

protected RecyclerHeaderViewListAdapter wrapHeaderListAdapterInternal(

ArrayList headerViewInfos,

ArrayList footerViewInfos,

Adapter adapter) {

return new RecyclerHeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter);

}

}

这就是封装的RecyclerView,里面主要有三个方法addHeaderView、 addFooterView和重写的setAdapter。这里的唯一的思想就是偷梁换柱,当我们添加头部、尾部或者设置adapter时,真正的adapter并不是我们传入的adapter,而是重新new 了一个RecyclerHeaderViewListAdapter。这才是RecyclerView最终设置的adapter。

其实我们看到ListView也是通过这样子的思想来添加头部和尾部的。

bfd4e8ee3655912878bb8f2f0697ce06.png

这就是ListView的addHeaderView方法,它会偷偷的创建HeaderViewListAdapter这个adapter。最终添加的header和footer在HeaderViewListAdapter里面实现。

public class RecyclerHeaderViewListAdapter extends RecyclerView.Adapter {

private final ArrayList mHeaderViewInfos;//保存headerview数据

private final ArrayList mFooterViewInfos;//保存footerView数据

private RecyclerView.Adapter mAdapter; //用户自己构造的adapter

private static final int RECYCLER_HEADER_VIEW = 0x001;//headerview类型

private static final int RECYCLER_FOOTER_VIEW = 0x002;//footerView类型

/**

* 构造方法

* 初始化

* @param headerViewInfos

* @param footerViewInfos

* @param adapter

*/

public RecyclerHeaderViewListAdapter(ArrayList headerViewInfos,

ArrayList footerViewInfos,

RecyclerView.Adapter adapter) {

mAdapter = adapter;

if (headerViewInfos == null) {

mHeaderViewInfos = new ArrayList<>();

} else {

mHeaderViewInfos = headerViewInfos;

}

if (footerViewInfos == null) {

mFooterViewInfos = new ArrayList<>();

} else {

mFooterViewInfos = footerViewInfos;

}

}

/**

* 根据getItemViewType返回的条目类型

* 创建不同的itemview

* 传入的adapter,回调它的onCreateViewHolder即可

* @param parent

* @param viewType

* @return

*/

@Override

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

if (viewType == RECYCLER_HEADER_VIEW){

return new HeaderViewLayout(mHeaderViewInfos.get(0));

}else if (viewType == RECYCLER_FOOTER_VIEW){

return new HeaderViewLayout(mFooterViewInfos.get(0));

}

return mAdapter.onCreateViewHolder(parent,viewType);

}

/**

* 绑定数据

* headerview和footerview不需要绑定数据,直接return即可

* 传入的adapter需要回调它的onBindViewHolder即可

* @param holder

* @param position

*/

@Override

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

//header

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

}

/**

* 返回条目的类型

* 传入的adapter,回调它的getItemViewType即可

* @param position

* @return

*/

@Override

public int getItemViewType(int position) {

// Header

int numHeaders = getHeadersCount();

if (position < numHeaders) {

return RECYCLER_HEADER_VIEW;

}

// Adapter

final int adjPosition = position - numHeaders;

int adapterCount = 0;

if (mAdapter != null) {

adapterCount = mAdapter.getItemCount();

if (adjPosition < adapterCount) {

return mAdapter.getItemViewType(position);

}

}

// Footer (off-limits positions will throw an IndexOutOfBoundsException)

return RECYCLER_FOOTER_VIEW;

}

/**

* 总条目即:footerview的条目+headerview的条目+穿入的adapter条目

* @return

*/

@Override

public int getItemCount() {

if (mAdapter != null) {

return getFootersCount() + getHeadersCount() + mAdapter.getItemCount();

} else {

return getFootersCount() + getHeadersCount();

}

}

/**

* 获取headerview的条目

* @return

*/

public int getHeadersCount() {

return mHeaderViewInfos.size();

}

/**

* 获取footervie的条目

* @return

*/

public int getFootersCount() {

return mFooterViewInfos.size();

}

/**

* 这是footerview和headerview的ViewHolder需要

* 这里只是提供一个构造器即可,实际上用处不大

*/

private static class HeaderViewLayout extends RecyclerView.ViewHolder{

public HeaderViewLayout(View itemView) {

super(itemView);

}

}

}

这是实现添加header、footer和传入adapter的RecyclerHeaderViewListAdapter。具体的逻辑都在文件的注释里面有说明。逻辑是仿造ListView的HeaderViewListAdapter来实现的。

其实就是创建一个adapter,然后根据不同的条目类型来创建条目和绑定条目的数据即可。

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"

android:orientation="vertical"

tools:context="com.wrap.recycler.WrapRecyclerViewActivity">

android:id="@+id/wrap_recyclerview"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

这是布局文件

public class WrapRecyclerViewActivity extends AppCompatActivity {

private WrapMyRecyclerView mRecyclerView;

private MyAdapter mMyAdapter;

private List mList01 = new ArrayList<>();

private static final int WC = ViewGroup.LayoutParams.WRAP_CONTENT;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_wrap_recycler_view);

getData();

mRecyclerView = (WrapMyRecyclerView) this.findViewById(R.id.wrap_recyclerview);

mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

//加入headerView

ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(WC,WC);

ImageView headerView = new ImageView(this);

headerView.setImageResource(R.drawable.timg);

headerView.setLayoutParams(params);

mRecyclerView.addHeaderView(headerView);

//设置adapter

mMyAdapter = new MyAdapter(this,mList01);

mRecyclerView.setAdapter(mMyAdapter);

//加入footerView

params = new ViewGroup.LayoutParams(WC,WC);

ImageView footerView = new ImageView(this);

footerView.setImageResource(R.drawable.hhfj);

footerView.setLayoutParams(params);

mRecyclerView.addFooterView(footerView);

mMyAdapter.notifyDataSetChanged();

}

public void getData() {

for (int i = 0; i < 3; i++) {

String data ="adapter...." + i;

mList01.add(data);

}

}

}

使用直接调用addHeaderView、addFooterView即可。

除了这种方式来实现addHeaderView和addFooterView,另外一种方式就是封装Adapter来实现,原理还是保持不变:根据不同的条目类型来创建条目和绑定条目的数据。

public class MyCircleRecycViewAdapter extends RecyclerView.Adapter {

public List infos = null;

private Context mContext;

private ListViewImgLoader mLoader;

private View VIEW_FOOTER;//尾部

private View VIEW_HEADER;//头部

//Type

private int TYPE_NORMAL = 1000;

private int TYPE_HEADER = 1001;

private int TYPE_FOOTER = 1002;

private int tagType = TYPE_NORMAL;

public MyCircleRecycViewAdapter(Context context,List datas) {

this.infos = datas;

this.mContext = context;

mLoader = new ListViewImgLoader();

mLoader.setMemoryCacheSize(1024 * 1024);

mLoader.setVisibleItemCount(12);

}

@Override

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

if (viewType == TYPE_FOOTER) {

tagType = TYPE_FOOTER;

return new MyCircleItemHolder(VIEW_FOOTER);

} else if (viewType == TYPE_HEADER) {

tagType = TYPE_HEADER;

return new MyCircleItemHolder(VIEW_HEADER);

} else {

tagType = TYPE_NORMAL;

View view = LayoutInflater.from(mContext).inflate(R.layout.circle_gridview_items, parent,false);

return new MyCircleItemHolder(view);

}

}

@Override

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

if (!isHeaderView(position) && !isFooterView(position)) {

if (haveHeaderView()) position--;

MyCircleItemHolder viewHolder = (MyCircleItemHolder)holder;

CircleInfo.CirclePageInfo mInfo = infos.get(position);

setData(viewHolder,mInfo);

}

}

@Override

public int getItemCount() {

int count = (infos == null ? 0 : infos.size());

if (VIEW_FOOTER != null) {

count++;

}

if (VIEW_HEADER != null) {

count++;

}

return count;

}

@Override

public int getItemViewType(int position)

{

if (isHeaderView(position)) {

return TYPE_HEADER;

} else if (isFooterView(position)) {

return TYPE_FOOTER;

} else {

return TYPE_NORMAL;

}

}

public void addHeaderView(View headerView) {

if (haveHeaderView()) {

throw new IllegalStateException("hearview has already exists!");

} else {

//避免出现宽度自适应

ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(Utils.getRealPixel(30), Utils.getRealPixel(230));

headerView.setLayoutParams(params);

VIEW_HEADER = headerView;

notifyItemInserted(0);

}

}

public void addFooterView(View footerView) {

if (haveFooterView()) {

throw new IllegalStateException("footerView has already exists!");

} else {

ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

footerView.setLayoutParams(params);

VIEW_FOOTER = footerView;

// ifGridLayoutManager();

notifyItemInserted(getItemCount() - 1);

}

}

private boolean haveHeaderView() {

return VIEW_HEADER != null;

}

public boolean haveFooterView() {

return VIEW_FOOTER != null;

}

private boolean isHeaderView(int position) {

return haveHeaderView() && position == 0;

}

private boolean isFooterView(int position) {

return haveFooterView() && position == getItemCount() - 1;

}

private void setData(final MyCircleItemHolder viewHolder, final CircleInfo.CirclePageInfo mInfo) {

if(mInfo == null || mInfo == viewHolder.tagInfo)

{

return;

}else{

viewHolder.tagInfo = mInfo;

if(!StrUtils.isEnpty(mInfo.thread_unread)){

if(mInfo.thread_unread.equals("0")){

viewHolder.threaduUnreadTv.setVisibility(View.INVISIBLE);

}else{

viewHolder.threaduUnreadTv.setVisibility(View.VISIBLE);

viewHolder.threaduUnreadTv.setText(mInfo.thread_unread);

}

}else{

viewHolder.threaduUnreadTv.setVisibility(View.INVISIBLE);

}

if (!TextUtils.isEmpty(viewHolder.tagUrl)){

if(mInfo.circle_img_path != null && !(mInfo.circle_img_path.equals(viewHolder.tagUrl))){

setImage(viewHolder.mImageView,mInfo.circle_img_path);

}

}else{

setImage(viewHolder.mImageView,mInfo.circle_img_path);

}

if (!TextUtils.isEmpty(mInfo.circle_img_path)){

viewHolder.tagUrl = mInfo.circle_img_path;

}

if(mInfo.circleName != null){

if(mInfo.circleName.length() > 5){

String s = mInfo.circleName.substring(0,5) + "...";

viewHolder.textView.setText(s);

}else{

viewHolder.textView.setText(mInfo.circleName);

}

}

}

}

private void setImage(final ColorFilterImageView mImageView, final String imgUrl){

mImageView.setBackgroundColor(0xffadadad);

mImageView.setImageBitmap(null);

if(!TextUtils.isEmpty(imgUrl))

{

mLoader.loadImage(mImageView.hashCode(), imgUrl, 300, new DnImg.OnDnImgListener()

{

@Override

public void onProgress(String url, int downloadedSize, int totalSize)

{

// TODO Auto-generated method stub

}

@Override

public void onFinish(String url, String file, Bitmap bmp)

{

if(url.equals(imgUrl))

{

mImageView.setImageBitmap(bmp);

}

}

});

}else{

mImageView.setBackgroundColor(0xffadadad);

mImageView.setImageBitmap(null);

}

}

class MyCircleItemHolder extends RecyclerView.ViewHolder{

private ColorFilterImageView mImageView;

private TextView textView;

private CircleInfo.CirclePageInfo tagInfo;

private String tagUrl;

private TextView threaduUnreadTv;

public MyCircleItemHolder(final View itemView) {

super(itemView);

if(tagType == TYPE_NORMAL){

mImageView = (ColorFilterImageView)itemView.findViewById(R.id.quan_icon);

mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);

textView = (TextView)itemView.findViewById(R.id.quan_name);

threaduUnreadTv = (TextView)itemView.findViewById(R.id.quan_num);

mImageView.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

if (mListener != null){

mListener.oncliItem(itemView,tagInfo,threaduUnreadTv);

}

}

});

}

}

}

public OnclickMyCircleItemListener mListener;

public void setOnclickMyCircleItemListener(OnclickMyCircleItemListener l){

this.mListener = l;

}

public interface OnclickMyCircleItemListener{

void oncliItem(View view,CircleInfo.CirclePageInfo info,View threadNumTv);

}

public void pauseLoader(){

if(mLoader != null)

{

mLoader.pause();

}

}

public void resumeLoader(){

if(mLoader != null)

{

mLoader.resume();

}

}

public void closeLoader(){

if(mLoader != null)

{

mLoader.close();

}

}

}

总结

以上就是这篇文章的全部内容了,希望本文的内容对各位Android开发者们的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值