RecycleView 是2014年Google IO 引入的新的控件,它是以 v7 support libraries的形式存在的,可以用在之前的Android系统版本。它的引入主要是用于增强ListView的功能。与其它的View不一样的地方是RecyclerView不负责子view的展现和布局工作,它关注的是子view的回收与复用。而子view的布局、装饰、动画都交给了其内部类来负责。

ViewHolder :用来放置每个item所包含子view的容器。在Adapter中负责创建和填充ViewHolder
Adapter :用于绑定数据和ViewHolder
LayoutManager :布局管理器,负责子View的位置安排
ItemDecoration :用来装饰子view
ItemAnimator :用于添加子View,增加删除的动画

RecycleView的简单使用

下面就由简单到复杂一步一步介绍它的使用。

1.在项目中引入recycleview的依赖关系。

compile 'com.android.support:recyclerview-v7:23.4.0'

如果大家不是很清楚recycleview的版本号的话,可以使用project structrue -> dependencies 输入recycleview,这时候会自动帮你查找对应的版本。

  1. Adapter 负责生成出绑定数据后的ViewHolder,它继承自RecyclerView.Adapter,一般而言它有一个构造方法用于用于传入两个参数,一个是上下文内容,一个是数据列表,还可以有另外一个参数用于传入布局id。
    public class MyRecycleViewAdapter extends RecyclerView.Adapter<MyRecycleViewAdapter.ViewHolder> {

    private Context mContext;
    private ArrayList<String> mList;
    MyRecycleViewAdapter(Context context, List<String> list) {
    mContext = context;
    mList = (ArrayList<String>) list;
    }
    }
    由于它继承自RecyclerView.Adapter所以必须覆写:
    onCreateViewHolder
    onBindViewHolder
    getItemCount
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater mInflater = LayoutInflater.from(parent.getContext());
    View itemView = mInflater.inflate(R.layout.recycleview_item, parent, false);
    return new ViewHolder(itemView);
    }
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
    String content = mList.get(position);
    holder.mContentView.setText(content);
    }
    @Override
    public int getItemCount() {
    return mList.size();
    }
    onCreateViewHolder 负责使用item layout 初始化出一个ItemView,再将ItemView传入ViewHoder,在ViewHolder中创建出构成ItemView的每个子View然后作为参数传递给onBindViewHolder,onBindViewHolder有两个参数,一个是onCreateViewHolder创建的ViewHolder,另一个是数据对应的位置,可以通过第二个参数重数据源中取出数据,然后和ViewHoder中的控件绑定。

下面是ViewHolder的实现:

public class ViewHolder extends RecyclerView.ViewHolder {
public TextView mContentView;
public ViewHolder(View itemView) {
super(itemView);
mContentView = (TextView) itemView.findViewById(R.id.listview_item);
}
}

最后初始化整个RecycleView:

public class MainActivity extends AppCompatActivity {
private RecyclerView mRecycleView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecycleView = (RecyclerView) findViewById(R.id.recycle_view);
mRecycleView.setLayoutManager(new GridLayoutManager(this,2));
List<String> stringlist = new ArrayList<>();
for(int i =0;i<100;i++) {
stringlist.add("Item " + i);
}
mRecycleView.setAdapter(new MyRecycleViewAdapter(this,stringlist));
mRecycleView.setItemAnimator(new DefaultItemAnimator());
}
}

RecycleView组成

RecyclerView.LayoutManager
RecyclerView.ItemDecoration
RecyclerView.ItemAnimator
ItemAnimator 用于在往RecycleView中添加删除或者移动Item的时候添加动画。默认情况下使用的是DefaultItemAnimator,在实际项目的时候会需要实现这个部分,如果大家有这种需求可以参考:
https://github.com/wasabeef/recyclerview-animators

多类型Item布局

在RecyclerView.Adopter中要实现多类型Item布局需要覆写如下方法:

public int getItemViewType(int position)  

并按照如下方法重新修改Adapter:

public class MyRecycleViewAdapter extends
/*这里改为RecyclerView.ViewHolder 因为这时候需要两个ViewHoder*/
RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private ArrayList<String> mList;
/*定义一个枚举类型用于指定item的类型*/
private enum ITEM_TYPE {
TYPE_ONE,
TYPE_TWO
};
/*根据对应的position返回当前的item类型*/
@Override
public int getItemViewType(int position) {
return (position % 2 == 0) ? ITEM_TYPE.TYPE_ONE.ordinal():ITEM_TYPE.TYPE_TWO.ordinal();
}

MyRecycleViewAdapter(Context context, List<String> list) {
mContext = context;
mList = (ArrayList<String>) list;
}

/*根据对应的viewType创建并返回对应的ViewHolder*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater mInflater = LayoutInflater.from(parent.getContext());
View itemView = null;
if(viewType == ITEM_TYPE.TYPE_ONE.ordinal()) {
itemView = mInflater.inflate(R.layout.recycleview_item, parent, false);
return new ViewHolder(itemView);
}else{
itemView = mInflater.inflate(R.layout.recycleview_two, parent, false);
return new ViewHolderTwo(itemView);
}
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
String content = mList.get(position);
if(holder instanceof MyRecycleViewAdapter.ViewHolder) {
((ViewHolder) holder).mContentView.setText(content);
}else if(holder instanceof MyRecycleViewAdapter.ViewHolderTwo) {
((ViewHolderTwo) holder).mImageView.setImageResource(R.mipmap.ic_launcher);
((ViewHolderTwo) holder).mContentView.setText(content);
}
}

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

public class ViewHolder extends RecyclerView.ViewHolder {
public TextView mContentView;
public ViewHolder(View itemView) {
super(itemView);
mContentView = (TextView) itemView.findViewById(R.id.listview_item);
}
}
public class ViewHolderTwo extends RecyclerView.ViewHolder {
public TextView mContentView;
private ImageView mImageView;
public ViewHolderTwo(View itemView) {
super(itemView);
mImageView = (ImageView) itemView.findViewById(R.id.imageicon);
mContentView = (TextView) itemView.findViewById(R.id.itemtext);
}
}
}

添加ItemDecoration

首先创建一个新的类继承自RecyclerView.ItemDecoration。
https://gist.github.com/alexfu/0f464fc3742f134ccd1e/

class ItemDecortion extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public ItemDecortion(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}

public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}

@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}

public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
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.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
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 left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}

然后在设置adapter之前,使用addItemDecoration()方法添加分割线.

mRecycleView.addItemDecoration(new ItemDecortion(this,ItemDecortion.VERTICAL_LIST));
mRecycleView.setAdapter(new MyRecycleViewAdapter(this,stringlist));
添加点击事件:

ListView 和RecycleView最大的不同就是没有OnItemClickListener来识别item的点击,我们必须自己通过扩展RecyclerView.OnItemTouchListener类来实现这个功能。

private interface onClickListener {
public void onClick(View view, int position);
public void onLongClick(View view,int position);
}
public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private MainActivity.onClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final MainActivity.onClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildPosition(child));
}
}
});
}
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildPosition(child));
}
return false;
}
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}

public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

}
}
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new ClickListener() {
public void onClick(View view, int position) {
Movie movie = movieList.get(position);
Toast.makeText(getApplicationContext(), movie.getTitle() + " is selected!", Toast.LENGTH_SHORT).show();
}
public void onLongClick(View view, int position) {

}
}));

增删改Item项

在ListView中每当Adapter数据项改变的时候一般执行notifyDataSetChanged()来通知数据集的改变,但是RecyclerView.Adapter 提供了 notifyItemInserted(), notifyItemChanged() 和 notifyItemRemoved()三个方法来通知数据集的修改。

Contents
  1. 1. RecycleView的简单使用
  2. 2. RecycleView组成
  3. 3. 多类型Item布局
  4. 4. 添加ItemDecoration
    1. 4.1. 添加点击事件:
  5. 5. 增删改Item项