一. RecycleView和ListView的区别
前两天面试,面试官问我,“ListView和RecycleView都用过吧,你是怎么选的?”。当时有点懵比,扯了一通,最后又引出了几个问题“RecycleView相比ListView哪方面性能更好,如何获取第一个可见的Item,如何给RecycleView添加headerView?”。谈到添加headerView,我说把第一个Item作为headerView的思路,又问“每个Item都对应一个数据info,headerView的没有用,会不会浪费,该怎么处理?。。”;问题虽然不能,但是因为没有比较过两者,加上对二者的某些API也不熟,整个回答过程磕磕绊绊,令人失望。在此,做一下总结,内容不全,以后了解到更多,再继续添加。
二. 抽象ViewHolder,增加RecycleView的可扩展性,阅读性
1.抽象出ViewHolder,定义一个数据类型接口,来区分出不同类型
public class BaseViewHolder extends RecyclerView.ViewHolder {
public BaseViewHolder(View itemView) {
super(itemView);
}
public void FillView(IData data){
}
}
数据类型接口IData.java,传递给adapter的数据要实现该接口,每个ViewHolder的Item实体数据类都实现该接口,同时返回不同类型值,以便在创建具体ViewHolder时,根据类型加载不同的ViewHolder。
public interface IData {
int typ();
}
传递数据的实体类,跟具体的ViewHolder相对应:
Info1:
public class Info1 implements IData {
@Override
public int typ() {
return RecycleItemTypeConstant.RECYCLEVIEW_ITEM_TYPE_1;
}
private int left_icon_id;
private String center_str;
private String right_str;
public int getLeft_icon_id() {
return left_icon_id;
}
public void setLeft_icon_id(int left_icon_id) {
this.left_icon_id = left_icon_id;
}
public String getCenter_str() {
return center_str;
}
public void setCenter_str(String center_str) {
this.center_str = center_str;
}
public String getRight_str() {
return right_str;
}
public void setRight_str(String right_str) {
this.right_str = right_str;
}
}
Info2:
public class Info2 implements IData {
@Override
public int typ() {
return RecycleItemTypeConstant.RECYCLEVIEW_ITEM_TYPE_2;
}
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
2.继承BaseViewHolder,实现不同布局:
如:ViewHolder1
public class ViewHolder1 extends BaseViewHolder {
private ImageView leftIcon;
private TextView centerTitle;
private TextView rightTitle;
public ViewHolder1(View itemView) {
super(itemView);
leftIcon=itemView.findViewById(R.id.recycle_item_left_icon);
centerTitle=itemView.findViewById(R.id.recycle_item_center_title);
rightTitle=itemView.findViewById(R.id.recycle_item_right_title);
}
@Override
public void FillView(IData data) {
super.FillView(data);
if (data instanceof Info1){
leftIcon.setImageResource(((Info1) data).getLeft_icon_id());
centerTitle.setText(((Info1) data).getCenter_str());
rightTitle.setText(((Info1) data).getRight_str());
}
}
}
ViewHolder2:
public class ViewHolder2 extends BaseViewHolder {
private TextView title;
public ViewHolder2(View itemView) {
super(itemView);
title=itemView.findViewById(R.id.recycle_item_center_title);
}
@Override
public void FillView(IData data) {
super.FillView(data);
title.setText(((Info2)data).getTitle());
}
}
等等,根据需要,添加多个。添加新的样式,只要添加一个新的ViewHolder对象,并稍微修改一下adapter即可
3.实现adapter:
public class RecycleAdapter extends RecyclerView.Adapter<BaseViewHolder> {
private List<IData>listDatas;
private Context mContext;
public RecycleAdapter(List<IData> listDatas, Context mContext) {
this.listDatas = listDatas;
this.mContext = mContext;
}
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
BaseViewHolder viewHolder=null;
switch (viewType){
case RecycleItemTypeConstant.RECYCLEVIEW_ITEM_TYPE_1:
viewHolder=onCreateViewHolder1(parent);
break;
case RecycleItemTypeConstant.RECYCLEVIEW_ITEM_TYPE_2:
viewHolder=onCreateViewHolder2(parent);
break;
case RecycleItemTypeConstant.RECYCLEVIEW_ITEM_TYPE_3:
viewHolder=onCreateViewHolder3(parent);
break;
default:
viewHolder=onCreateDefaultViewHolder(parent);
break;
}
return viewHolder;
}
private BaseViewHolder onCreateDefaultViewHolder(ViewGroup parent){
TextView textView = new TextView(mContext);
BaseViewHolder holder = new BaseViewHolder(textView);
return holder;
}
private BaseViewHolder onCreateViewHolder1(ViewGroup parent){
View itemView= LayoutInflater.from(mContext).inflate(R.layout.layout_type_1,parent,false);
ViewHolder1 viewHolder=new ViewHolder1(itemView);
return viewHolder;
}
private BaseViewHolder onCreateViewHolder2(ViewGroup parent){
View itemView= LayoutInflater.from(mContext).inflate(R.layout.layout_type_2,parent,false);
ViewHolder2 viewHolder=new ViewHolder2(itemView);
return viewHolder;
}
private BaseViewHolder onCreateViewHolder3(ViewGroup parent){
View itemView= LayoutInflater.from(mContext).inflate(R.layout.layout_type_3,parent,false);
ViewHolder3 viewHolder=new ViewHolder3(itemView);
return viewHolder;
}
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
try {
holder.FillView(listDatas.get(position));
}catch (Exception e){
Log.i("RecycleView","onLayout Error: " + e.toString() + "for holder: "
+ holder.getClass().getSimpleName());
}
}
@Override
public int getItemCount() {
return listDatas.size();
}
@Override
public int getItemViewType(int position) {
if (position<0||position>listDatas.size()-1){
return -1;
}
return listDatas.get(position).typ();
}
}
4.使用,在传给adapter的数据集合中,添加每种类型的数据,即会创建相应布局的Item:
如:
datas=new ArrayList<>();
Info1 info1=new Info1();
info1.setCenter_str("种类1");
info1.setRight_str("右边");
info1.setLeft_icon_id(R.mipmap.ic_launcher);
Info2 info2=new Info2();
info2.setTitle("卡片2");
Info3 info3=new Info3();
info3.setCenter_str("3");
info3.setRight_str("右边");
info3.setLeft_icon_id(R.mipmap.ic_launcher);
datas.add(info1);
datas.add(info2);
datas.add(info3);
三. 自定义ItemDecoration
通过自定义ItemDecoration可实现,RecycleView各种各样的分割线。自定义ItemDecoration,通过复写他的三个方法就可快速实现。其中,要注意的是:getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)的outRect相当于margin,通过设置他,可控制Item view距离上下,左右的距离;onDraw()方法是在Item:
API关于onDraw()的说明: 他是在item被绘制前绘制的,因此如果onDraw的绘制位置和Item的位置位置重叠,就会被覆盖,这也是,为什么我们要在getItemOffsets中设置outRect,来实现边距的原因(个人理解,不知对否)。我们在onDraw中实现绘制时就在留出的空间中进行绘制。至于绘制,完全就是利用Canvas进行绘制,可根据需求,各种绘画。
/**
* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
* Any content drawn by this method will be drawn before the item views are drawn,
* and will thus appear underneath the views.
*
* @param c Canvas to draw into
* @param parent RecyclerView this ItemDecoration is drawing into
* @param state The current state of RecyclerView
*/
public void onDraw(Canvas c, RecyclerView parent, State state) {
onDraw(c, parent);
}
onDrawOver()是在item绘制之后调用,绘制在它上面。绘制起来和onDraw一样,也是使用canvas想怎么绘怎么绘。
/**
* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
* Any content drawn by this method will be drawn after the item views are drawn
* and will thus appear over the views.
*
* @param c Canvas to draw into
* @param parent RecyclerView this ItemDecoration is drawing into
* @param state The current state of RecyclerView.
*/
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
onDrawOver(c, parent);
}
最后,是一个小demo,自定义ItemDecoration如下
public class CustomItemDecoration extends RecyclerView.ItemDecoration {
Paint mPaint;
public CustomItemDecoration() {
super();
mPaint=new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL);
}
/**
*在itemView绘制之前绘制,所以要通过getItemOffsets设置好距离,留出空间,防止被后绘得的itemView覆盖掉
* @param c
* @param parent
* @param state
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
// int childCount = parent.getChildCount();
// for ( int i = 0; i < childCount; i++ ) {
// View view = parent.getChildAt(i);
// int index = parent.getChildAdapterPosition(view);
// float top = view.getBottom();
// float extra=view.getHeight()/2;
// c.drawCircle(50, top+extra,20,mPaint);
// }
}
/**
* 在itemVie上面绘制,根据设计,使用canvas进行绘制即可
* @param c
* @param parent
* @param state
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
int childCount = parent.getChildCount();
for ( int i = 0; i < childCount; i++ ) {
View view = parent.getChildAt(i);
int index = parent.getChildAdapterPosition(view);
float top = view.getTop();
float extra=view.getHeight()/2;
c.drawCircle(50, top+extra,20,mPaint);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (parent.getChildAdapterPosition(view)!=0) {
outRect.top = 10;
outRect.left=100;
}
}
}
效果如下:
主要参考文章:
小甜点,RecyclerView 之 ItemDecoration 讲解及高级特性实践,作者讲的非常详尽易懂。