RecyclerView的基本使用
(一) 介绍
RecyclerView是V7包下的一个控件,由于其出色的缓存策略,滑动流畅性特别好。google建议用来替换目前的ListView和GridView ,总结下RecyclerVie有以下特点:
1 通过LayoutManger轻松替代ListView和GridView
2 通过ItemDecoration实现每个item之间的分隔线
3 通过ItemAnimator实现各种炫酷的动画效果
4 但是item的点击,长按,焦点变化监听要自己去添加
(二) 替代ListView效果
mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
//线性排列
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//设置item添加和删除动画效果
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//添加分隔线
mRecyclerView.addItemDecoration(new DividerItemDecoration(MainActivity.this,DividerItemDecoration.VERTICAL_LIST));
mAdapter = new HomeAdapter();
mRecyclerView.setAdapter(mAdapter);
(三)GridView效果
mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
//设置分隔线
mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));
//设置item添加和删除动画效果
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//设置GridView的布局和item排列的方向
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL));
mAdapter = new HomeAdapter();
mRecyclerView.setAdapter(mAdapter);
RecyclerView的强大之处在于:它只负责回收View,至于布如何Layout,分隔线如何显示,动画效果都可以来定制来实现。
(四) Adapter的使用
RecyclerView自己默认有一个Adapter,并与强制与ViewHolder进行绑定
class HomeAdapter extends RecyclerView.Adapter {
//创建ViewHolder调用
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
MainActivity.this).inflate(R.layout.item_home, parent,
false));
return holder;
}
//绑定ViewHolder,展示数据
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv.setText(mDataList.get(position));
}
//返回item总个数
@Override
public int getItemCount() {
return mDataList.size();
}
class MyViewHolder extends ViewHolder {
TextView tv;
public MyViewHolder(View view) {
super(view);
tv = (TextView) view.findViewById(R.id.id_num);
}
}
}
adapter提供了以下2个方法来删除和添加item,并且RecyclerView会默认加上动画效果
mAdapter.notifyItemInserted(int position);
mAdapter.notifyItemRemoved(int position);
(五)给RecyclerView添加事件
package test.lesports.com.recicleview;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by liuyu8 on 2016/1/2.
*/
class HomeAdapter extends RecyclerView.Adapter {
private List mDataList = new ArrayList();
private OnItemClickListener mOnItemClickListener;
private LayoutInflater mInflater;
private OnItemFocusChange mOnItemFocusChange;
public HomeAdapter(Context context, List list) {
this.mInflater = LayoutInflater.from(context);
this.mDataList = list;
}
public void setDataList(List list) {
this.mDataList = list;
}
/**
* 添加Item
*/
public void addItem(int position) {
mDataList.add(position, "Insert One");
notifyItemInserted(position);
}
/**
* 删除item
*
* @param position
*/
public void removeItem(int position) {
mDataList.remove(position);
notifyItemRemoved(position);
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
public interface OnItemFocusChange {
void onItemFocusChange(View view, boolean hasFocus, int position);
}
public void setOnItemClickListener(OnItemClickListener mOnClickListener) {
this.mOnItemClickListener = mOnClickListener;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
MyViewHolder holder = new MyViewHolder(mInflater.inflate(R.layout.item_home, parent,
false));
return holder;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.tv.setText(mDataList.get(position));
if (mOnItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(holder.itemView, holder.getLayoutPosition());
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
//这里返回的position为holder.getLayoutPosition()为好,
// 因为当添加item后,如果没有adapter没有调用setNotifyDataChange()
// 的话,position的值是错误的
mOnItemClickListener.onItemLongClick(view, holder.getLayoutPosition());
return true;
}
});
if (mOnItemFocusChange != null) {
holder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
mOnItemFocusChange.onItemFocusChange(v, hasFocus, holder.getLayoutPosition());
}
});
}
}
}
@Override
public int getItemCount() {
return mDataList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv;
public MyViewHolder(View view) {
super(view);
tv = (TextView) view.findViewById(R.id.id_num);
}
}
}
(六)分隔线(RecyclerView.ItemDecoration)
通过ItemDecoration可以使各个Item在视觉上相互分开,其实和ListView的Divider很像。ItemDecoration并不是RecyclerView必须设置的,开发者可以不设置或者设置多个Decoration。RecyclerView会遍历所有的ItemDecoration并调用各自的绘图方法。
继承ItemDecoration需要实现以下三个方法:
public void onDraw(Canvas c,RecyclerView parent,RecyclerView.State state)
public void getItemOffset(Rect outRect,int itemPosition,RecyclerView parent)
LayoutManager会调用getItemOffset方法来计算每个Item的Decoration合适的尺寸。
Demo中自定义了一个ItemDecoration来实现ListView的Divider效果:
package test.lesports.com.recicleview;
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.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
/**
* This class is from the v7 samples of the Android SDK. It's not by me!
*
* See the license above for details.
*/
public class DividerItemDecoration 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 DividerItemDecoration(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 onDraw(Canvas c, RecyclerView parent) {
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);
android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());
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, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}