RecycleView使用总结一

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


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页