一. 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 讲解及高级特性实践,作者讲的非常详尽易懂。