一、RecycleView简要介绍
RecycleView是support-v7包中的新组件,是一个强大的滑动组件。相比于ListView和GridView具有很多让开发者喜欢的优点,如:数据绑定,Item的创建和View的回收复用机制等。但RecycleView更加高级灵活,当我们数据因为用户事件或者网络事件发生改变的时候也能很好的进行显示。RecycleView最主要的特点就是复用。
二、RecycleView与ListView区别
RecycleView是ListView的升级版,与经典的ListView相比,同样具有item的回收复用功能。
1.RecycleView封装了ViewHolder的回收复用,标准化了ViewHolder,编写Adapter面向的是ViewHolder,而不是View,高度解耦,复用的逻辑被封装,给编写代码带来更大的方便。
2.RecycleView提供了一种插拔式的体验,高度解耦,异常灵活,为了来控制item的显示,RecycleView针对一个Item的显示专门抽取了相应的类,使其扩展性非常强。
3.可以控制Item增减动画,可以通过ItemAnimation来进行控制。当然,RecycleView有其自己默认的实现方式。
4.使用LayoutManager来确定每一个item的排列方式。
5.在使用RecycleView之前,需要继承RecycleView.Adapter适配,将数据与每个item进行绑定。
6.利用LayoutManager确定每一个item如何摆放、何时展示与隐藏。或者回收复用View的时候,LayoutManager回想适配器请求新的数据来替换以前的数据,该机制避免了创建过多的View和频繁调用Id方法。
三、Recycle基本用法
1.在项目gradle下添加依赖。
compile ‘com.android.support:recyclerview-v7:25.0.1‘
2.实现RecycleView布局。
<android.support.v7.widget.RecyclerView android:id="@+id/id_recyclerview" android:divider="#ffff0000" android:dividerHeight="10dp" android:layout_width="match_parent" android:layout_height="match_parent" />
3.设置布局管理器。布局主要有三种实现方式,本文采用流式布局进行解析。
mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); //线性布局 mRecyclerView.setLayoutManager(new GridLayoutManager(this, 4)); //网格 mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL)); //流式布局
4.设置Adapter与ViewHolder进行事件绑定。
@Override public void onBindViewHolder(final MyViewHolder holder, int position) { ViewGroup.LayoutParams lp = holder.tv.getLayoutParams(); if(position != 0 && position < mDatas.size()){ lp.height = mHeights.get(position); holder.tv.setLayoutParams(lp); } holder.tv.setText(mDatas.get(position)); }
5.setAdapter与设置分割线、Item动画。
mAdapter = new HomeAdapter(this, mDatas); mAdapter.setOnItemClickListener(this); mRecyclerView.setAdapter(mAdapter); //设置默认分割线 // mRecyclerView.addItemDecoration(new DividerItemDecoration(this, // DividerItemDecoration.VERTICAL)); mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this)); //设置Item动画 mRecyclerView.setItemAnimator(new DefaultItemAnimator());
6.初始化数据。
private void initListData() { mDatas = new ArrayList<String>(); for (int i = ‘A‘; i <= ‘z‘; i++) { mDatas.add("" + (char) i); } }
7.设置Item点击事件(增加Item)。RecycleView没有像ListView一样给我提供一个onItemClickListener内置监听器,当我们点击item触发事件的时候会回调相关方法,不过我们可以改造Adapter以达到我们的目的。
holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int pos = holder.getLayoutPosition(); listener.OnItemClick(holder.itemView, pos); addData(pos); } });
public void addData(int position) { mDatas.add(position, "Insert One"); notifyItemInserted(position); }
8.设置长按点击事件(移除Item)。同7一样,主要是使用RecycleView方法添加和删除数据。与ListView不同的是,ListView在数据发生变化的时候采用的是notifyDatasetChange方法刷新数据,但RecycleView采用更高级的方法notifyItemInserted(position)和notifyItemRemoved(position)来进行添加和删除的数据刷新。
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { int pos = holder.getLayoutPosition(); listener.onItemLongClick(holder.itemView, pos); removeData(pos); return false; } });
public void removeData(int position) { mDatas.remove(position); notifyItemRemoved(position); }
9.分割线的封装。
package example.com.demo_recycleview; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.View; public class DividerGridItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[] { android.R.attr.listDivider }; private Drawable mDivider; public DividerGridItemDecoration(Context context) { final TypedArray array = context.obtainStyledAttributes(ATTRS); mDivider = array.getDrawable(0); array.recycle(); } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { drawHorizontal(c, parent); drawVertical(c, parent); } private int getSpanCount(RecyclerView parent) { // 列数 int spanCount = -1; RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); } else if (layoutManager instanceof StaggeredGridLayoutManager) { spanCount = ((StaggeredGridLayoutManager) layoutManager) .getSpanCount(); } return spanCount; } public void drawHorizontal(Canvas c, RecyclerView parent) { int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getLeft() - params.leftMargin; final int right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawVertical(Canvas c, RecyclerView parent) { final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getTop() - params.topMargin; final int bottom = child.getBottom() + params.bottomMargin; final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) { RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边 { return true; } } else if (layoutManager instanceof StaggeredGridLayoutManager) { int orientation = ((StaggeredGridLayoutManager) layoutManager) .getOrientation(); if (orientation == StaggeredGridLayoutManager.VERTICAL) { if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边 { return true; } } else { childCount = childCount - childCount % spanCount; if (pos >= childCount)// 如果是最后一列,则不需要绘制右边 return true; } } return false; } private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, int childCount) { RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { childCount = childCount - childCount % spanCount; if (pos >= childCount)// 如果是最后一行,则不需要绘制底部 return true; } else if (layoutManager instanceof StaggeredGridLayoutManager) { int orientation = ((StaggeredGridLayoutManager) layoutManager) .getOrientation(); // StaggeredGridLayoutManager 且纵向滚动 if (orientation == StaggeredGridLayoutManager.VERTICAL) { childCount = childCount - childCount % spanCount; // 如果是最后一行,则不需要绘制底部 if (pos >= childCount) return true; } else // StaggeredGridLayoutManager 且横向滚动 { // 如果是最后一行,则不需要绘制底部 if ((pos + 1) % spanCount == 0) { return true; } } } return false; } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { int spanCount = getSpanCount(parent); int childCount = parent.getAdapter().getItemCount(); if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部 { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边 { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight()); } } }
四、效果展示
五、源码下载
地址:http://download.csdn.net/detail/u012721519/9743570
Good luck!
Write by Jimmy.li