安卓开发(5):自定义RecyclerView.Adapter、RecyclerView和自定义RecyclerView.ViewHolder的使用

  • Post author:
  • Post category:其他


首先讲一下三者的关系,ViewGroup是一个可以包含很多个子View的类,每一个列表项都是作为一个View子对象显示的,每个View可以是简单的也可以是复杂的。

这里假设每个View都是一个TextView,而且一个屏幕可以显示10个TextView

,现在有上百个TextView要显示,那是不是意味着要准备上百个TextView呢?不是,这里涉及到回收利用的思想,并且已经封装成了RecylerView类。RecyclerView可以创建刚刚好充满屏幕的10个视图,用户滑动屏幕切换视图时,上一个视图就被回收利用并且加载下一个将要显示的视图。

RecyclerView的任务就是

回收和定位屏幕上的View


列表项View显示数据涉及

Adapter和ViewHolder。

ViewHolder只做一件事,就是

容纳View视图。


RecyclerView并不会创建视图,它创建的是ViewHolder,而ViewHolder分别引用着一个个itemView。不过

RecyclerView自己也是不直接创建ViewHolder

的,这个任务是adapter完成的。Adapter是一个控制器(适配器)对象,从模型层获取数据,然后提供给RecyclerView显示,起到桥梁的作用。

Adapter负责任务有2个:


1.创建必要的ViewHolder;



2.绑定ViewHolder到模型层数据。

.

创建Adapter,首先要定义RecyclerView.Adapter,然后由他封装获取的数据。

RecyclerView要视图时,就会去找它的Adapter:

1)先调用Adapter的getItemCount()方法,询问数组列表中的对象数量。

2)RecyclerView调用adapter的createViewHolder(ViewGroup,int)方法创建ViewHolder以及ViewHolder要显示的视图。

3)RecyclerView会传入ViewHolder及其位置,调用onBindViewHolder(ViewGroup,int)方法。adapter会找到目标位置的数据并且绑定到ViewHolder视图上。绑定就是使用模型数据填充视图。

三个过程完成后,RecyclerView就能在屏幕上显示View了,另外createViewHolder以及onBindViewHolder使用并不频繁。创建了够用的ViewHolder就停止调用了。然后会自动回收旧的ViewHolder来节约时间和节省内存。

1.RecyclerView的使用:

在project的build.gradle添加:

allprojects {
    repositories {
        jcenter()
        maven{
            url "https://maven.google.com"
        }
    }
}

在app的

build.gradle添加:

    compile 'com.android.support:cardview-v7:26.+'
    compile 'com.android.support:recyclerview-v7:26.+'

布局文件中这样引用:

<android.support.v7.widget.RecyclerView
        android:id="@+id/shoppinglist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="visible"
        />

这样就创建了一个空的

RecyclerView,在代码中获取

RecyclerView后,设置其显示方式:








然后使用Adapter为它填充数据:

mRecyclerView.setAdapter(mAdapter);





RecyclerView中必须自定义实现

RecyclerView.Adapter提供数据集合,实现时要遵循ViewHolder设计模式。



2.自定义RecyclerView.ViewHolder,代码中就是以上思想的实现

public class ViewHolder extends RecyclerView.ViewHolder {
    private SparseArray<View> mViews;//存储list_Item的View
    private View mConvertView;//list_Item
    public ViewHolder(Context context, View itemView, ViewGroup parent) {
        super(itemView);
        mConvertView=itemView;
        mViews=new SparseArray<View>();
    }
    //获取实例
    public static ViewHolder get(Context context,ViewGroup parent,int layoutId) {
        View itemView= LayoutInflater.from(context).inflate(layoutId,parent,false);
        ViewHolder holder=new ViewHolder(context,itemView,parent);
        return holder;
    }
    public <T extends View> T getView(int viewId) {
        View view=mViews.get(viewId);
        if(view==null) {
            view=mConvertView.findViewById(viewId);
            mViews.put(viewId,view);
        }
        return (T)view;
    }
}

3.自定义

RecyclerView.Adapter:

public abstract class CommonAdapter extends RecyclerView.Adapter<ViewHolder> {
    private List<Map<String,Object>> mdatas;//要显示的数据
    private OnItemClickListener mOnItemClickListener;//列表点击监听器
    private Context mContext;
    private int mLayoutId;
    public CommonAdapter(Context context,int layoutId,List datas) {
        mContext=context;
        mLayoutId=layoutId;
        mdatas=datas;
    }
    public void removeItem(int i) {//非必要,只是为了调用删除函数方便
        if(i>0) {
            mdatas.remove(i);
            notifyItemRemoved(i);
        }
    }
    //开始三个过程的实现
    @Override
    public int getItemCount() {
        return mdatas.size();
    }

    @Override
    public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
        ViewHolder viewHolder=ViewHolder.get(mContext,parent,mLayoutId);
        return viewHolder;
    }
    @Override
    public void onBindViewHolder(final ViewHolder holder,int position) {
        if(mOnItemClickListener!=null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mOnItemClickListener.onClick(holder.getAdapterPosition());
                }
            });
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    mOnItemClickListener.onLongClick(holder.getAdapterPosition());
                    return true;
                }
            });
        }
        convert(holder,mdatas.get(position));
    }

    public void convert(ViewHolder holder,Map<String,Object> s) {}//根据自己意愿绑定数据

    public interface OnItemClickListener{
        void onClick(int position);
        void onLongClick(int position);
    }
    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.mOnItemClickListener=onItemClickListener;
    }
}

在创建的时候重载convert函数(绑定数据到itemview上的哪里):

CommonAdapter commonAdapter=new CommonAdapter(this,R.layout.shoppinglist,listItems) {
            @Override
            public void convert(ViewHolder holder,Map<String,Object> s) {
                TextView name=holder.getView(R.id.goodsName);
                name.setText(s.get("name").toString());
                TextView first=holder.getView(R.id.goodsFirst);
                first.setText(s.get("firstLetter").toString());
            }
        };

利用所学可以实现一个小项目:

https://github.com/KingsonKai/AndroidProject/tree/master/Lab3



版权声明:本文为KingsonYing原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。