美文网首页
RecyclerView全解析

RecyclerView全解析

作者: fastcv | 来源:发表于2019-07-10 11:56 被阅读0次

    前言

    RecyclerView标准化了ViewHolder,可以轻松实现ListView实现不了的样式和功能,通过布局管理器LayoutManager可控制Item的布局方式,通过设置Item操作动画自定义Item添加和删除的动画,通过设置Item之间的间隔样式,自定义间隔。

    那么,综合上面的特点,我们可以得到,RecyclerView的四大部分

    • 适配器
    • LayoutManager控制布局样式
    • 自定义Item间隔线
    • 添加动画

    那我们来分别学习一下。

    添加依赖:

     implementation 'androidx.recyclerview:recyclerview:1.0.0'
    

    适配器的使用

    在RecyclerView中,适配器的一些基本的封装都已经被做好了,我们定义一个类去继承RecyclerView.Adapter<T extends RecyclerView.ViewHolder>,然后去实现相应的方法即可。

    继承RecyclerView.Adapter

    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return null;
        }
    
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    
        }
    
        @Override
        public int getItemCount() {
            return 0;
        }
    
        class ViewHolder extends RecyclerView.ViewHolder {
    
            public ViewHolder(@NonNull View itemView) {
                super(itemView);
            }
        }
    }
    

    我们来分别了解下其中的几个方法:

    • 自己的ViewHolder的ViewHolder(@NonNull View itemView)方法:这个方法就是用来存储我们的item的
    • onCreateViewHolder:顾名思义,使用来创建实例化我们的viewholder对象的,我们可以在里面这么操作
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info,parent,false);
            ViewHolder viewHolder = new ViewHolder(view);
            return viewHolder;
        }
    

    这样子,我们就将我们的item对象传到viewholder里面了。

    • 初始化viewholder:我们从onCreateViewHolder中得到viewHolder对象后,对item里面的组件进行初始化,那我们的viewholder修改之后为
    class ViewHolder extends RecyclerView.ViewHolder {
    
            TextView item_tv_explain;
            TextView item_tv_key;
            TextView item_tv_value;
    
            public ViewHolder(@NonNull View itemView) {
                super(itemView);
                item_tv_explain = itemView.findViewById(R.id.item_tv_explain);
                item_tv_key = itemView.findViewById(R.id.item_tv_key);
                item_tv_value = itemView.findViewById(R.id.item_tv_value);
            }
        }
    
    • getItemCount方法:这个方法是用来得到我们的list数量大小的,所以,我们需要在Adapter的构造方法里面传入我们需要数据源,然后在这个方法里面返回大小,如:
     ArrayList<RequestEntity> list_request;    //总的请求信息
    
        public MyAdapter(ArrayList<RequestEntity> list_request) {
            this.list_request = list_request;
        }
    
     public int getItemCount() {
            return list_request == null ? 0 : list_request.size();
        }
    
    • onBindViewHolder:这个方法就是用来绑定item的view和数据的,如
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.item_tv_explain.setText(list_request.get(position).explain);
            holder.item_tv_key.setText(list_request.get(position).key);
            holder.item_tv_value.setText(list_request.get(position).value);
        }
    

    这样子,我们就完成了适配器的编写

    附加:layout/item_request_info.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="match_parent"
        android:weightSum="10"
        android:background="#FFFFFF"
        android:layout_height="40dp">
    
        <TextView
            android:layout_width="0dp"
            android:layout_weight="2"
            android:gravity="center"
            android:id="@+id/item_tv_explain"
            android:layout_height="match_parent" />
    
        <TextView
            android:layout_width="0dp"
            android:layout_weight="4"
            android:gravity="center"
            android:id="@+id/item_tv_key"
            android:layout_height="match_parent" />
    
        <TextView
            android:layout_width="0dp"
            android:layout_weight="4"
            android:gravity="center"
            android:id="@+id/item_tv_value"
            android:layout_height="match_parent" />
    </LinearLayout>
    

    打造万能适配器

    万能ViewHolder

    public class ViewHolder extends RecyclerView.ViewHolder {
    
        View itemView;
        private SparseArray<View> mViews;
    
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            this.itemView = itemView;
            this.mViews = new SparseArray<>();
        }
    
        public static ViewHolder get(ViewGroup parent, int viewType) {
            View v;
            if(viewType == 1) {
                v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info1, parent, false);
            } else {
                v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info2, parent, false);
            }
            return new ViewHolder(v);
        }
    
        public ViewHolder setTextViewValue(int viewId,String text)
        {
            TextView tv = getView(viewId);
            tv.setText(text);
            return this;
        }
    
        private <T extends View> T getView(int viewId) {
            View view = mViews.get(viewId);
    
            if (view == null)
            {
                view = itemView.findViewById(viewId);
                mViews.put(viewId,view);
            }
            return (T) view;
        }
    }
    

    万能适配器

    public abstract class NetRvAdapter1<T> extends RecyclerView.Adapter<ViewHolder> {
    
        ArrayList<T> list_request;    //总的请求信息
    
        public NetRvAdapter1(ArrayList<T> list_request) {
            this.list_request = list_request;
        }
    
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return ViewHolder.get(parent,viewType);
        }
    
        @Override
        public int getItemViewType(int position) {
            // 瀑布流样式外部设置spanCount为2,在这列设置两个不同的item type,以区分不同的布局
            return position % 2;
        }
    
        public abstract void convert(ViewHolder holder,T t);
    
    
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            convert(holder,list_request.get(position));
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    if(onItemClickListener != null) {
                        int pos = holder.getLayoutPosition();
                        onItemClickListener.onItemLongClick(holder.itemView, pos);
                    }
                    //表示此事件已经消费,不会触发单击事件
                    return true;
                }
            });
        }
    
        @Override
        public int getItemCount() {
            return list_request == null ? 0 : list_request.size();
        }
    
        public void addNewItem(int index,T t) {
            if(list_request == null) {
                list_request = new ArrayList<>();
            }
            list_request.add(index, t);
            notifyItemInserted(index);
        }
    
        public void deleteItem(int index) {
            if(list_request == null || list_request.isEmpty()) {
                return;
            }
            list_request.remove(index);
            notifyItemRemoved(index);
        }
    
        /**
         * 事件回调监听
         */
        private NetRvAdapter1.OnItemClickListener onItemClickListener;
    
    
        /**
         * 设置回调监听
         *
         * @param listener
         */
        public void setOnItemClickListener(NetRvAdapter1.OnItemClickListener listener) {
            this.onItemClickListener = listener;
        }
    
        public interface OnItemClickListener {
            void onItemClick(View view, int position);
            void onItemLongClick(View view, int position);
        }
    }
    

    使用

    public class RealAdapter extends NetRvAdapter1<RequestEntity> {
    
        public RealAdapter(ArrayList<RequestEntity> list_request) {
            super(list_request);
        }
    
        @Override
        public void convert(ViewHolder holder, RequestEntity entity) {
    
            holder
                    .setTextViewValue(R.id.item_tv_explain,entity.explain)
                    .setTextViewValue(R.id.item_tv_key,entity.key)
                    .setTextViewValue(R.id.item_tv_value,entity.value);
        }
    }
    
    adapter = new RealAdapter(list_request);
    rv_request_details.setAdapter(adapter);
    

    选择LayoutManager控制布局样式

    RecyclerView提供了三种布局样式

    • LinerLayoutManager 以垂直或者水平列表方式展示Item
    • GridLayoutManager 以网格方式展示Item
    • StaggeredGridLayoutManager 以瀑布流方式展示Item

    我们首先来学习下LinerLayoutManager来实现垂直和水平方向展示item

    LinerLayoutManager

    垂直方向展示item

    我们继续使用上面的item布局文件,然后在MainActivity中编写代码,如:

     private void initView() {
            adapter = new NetRvAdapter(list_request);
            LinearLayoutManager layoutManager = new LinearLayoutManager(this);
            //设置布局管理器
            rv_request_details.setLayoutManager(layoutManager);
            //设置为垂直布局,这也是默认的
            layoutManager.setOrientation(OrientationHelper.VERTICAL);
            //设置Adapter
            rv_request_details.setAdapter(adapter);
        }
    

    截图:


    screen.png

    水平方向展示item

    我们修改item布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="60dp"
        android:weightSum="10"
        android:background="#FFFFFF"
        android:layout_height="match_parent">
    
        <TextView
            android:layout_width="match_parent"
            android:layout_weight="2"
            android:gravity="center"
            android:id="@+id/item_tv_explain"
            android:layout_height="0dp" />
    
        <TextView
            android:layout_width="match_parent"
            android:layout_weight="4"
            android:gravity="center"
            android:id="@+id/item_tv_key"
            android:layout_height="0dp" />
    
        <TextView
            android:layout_width="match_parent"
            android:layout_weight="4"
            android:gravity="center"
            android:id="@+id/item_tv_value"
            android:layout_height="0dp" />
    </LinearLayout>
    

    修改MainActivity中的代码,如:

    private void initView() {
            adapter = new NetRvAdapter(list_request);
            LinearLayoutManager layoutManager = new LinearLayoutManager(this);
            //设置布局管理器
            rv_request_details.setLayoutManager(layoutManager);
            //设置为垂直布局,这也是默认的
            layoutManager.setOrientation(OrientationHelper.HORIZONTAL);  //这里
            //设置Adapter
            rv_request_details.setAdapter(adapter);
        }
    

    截图:


    screen.png

    GridLayoutManager 以网格方式展示Item

    构造函数以及参数含义:

    • GridLayoutManager(Context context, int spanCount)
      • spanCount,每列或者每行的item个数,设置为1,就是列表样式
        该构造函数默认是竖直方向的网格样式
    • GridLayoutManager(Context context, int spanCount, int orientation,boolean reverseLayout)
      • spanCount,每列或者每行的item个数,设置为1,就是列表样式
        网格样式的方向,水平(OrientationHelper.HORIZONTAL)或者竖直(OrientationHelper.VERTICAL)
      • reverseLayout,是否逆向,true:布局逆向展示,false:布局正向显示

    使用

    修改布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:background="#FFFFFF"
        android:gravity="center"
        android:layout_height="100dp">
    
        <TextView
            android:layout_width="wrap_content"
            android:gravity="center"
            android:id="@+id/item_tv_explain"
            android:layout_height="wrap_content" />
    
        <TextView
            android:layout_width="wrap_content"
            android:gravity="center"
            android:id="@+id/item_tv_key"
            android:layout_height="wrap_content" />
    
        <TextView
            android:layout_width="wrap_content"
            android:gravity="center"
            android:id="@+id/item_tv_value"
            android:layout_height="wrap_content" />
    </LinearLayout>
    

    在MainActivity中设置

     // 竖直方向的网格样式,每行四个Item
            GridLayoutManager  mLayoutManager = new GridLayoutManager(this, 4, OrientationHelper.VERTICAL, false);
            rv_request_details.setLayoutManager(mLayoutManager);
    

    截图:


    screen.png

    StaggeredGridLayoutManager 以瀑布流方式展示Item

    我们新增两个布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:background="#03B8FF"
        android:gravity="center"
        android:layout_height="100dp">
    
        <TextView
            android:layout_width="wrap_content"
            android:gravity="center"
            android:id="@+id/item_tv_explain"
            android:layout_height="wrap_content" />
    
        <TextView
            android:layout_width="wrap_content"
            android:gravity="center"
            android:id="@+id/item_tv_key"
            android:layout_height="wrap_content" />
    
        <TextView
            android:layout_width="wrap_content"
            android:gravity="center"
            android:id="@+id/item_tv_value"
            android:layout_height="wrap_content" />
    </LinearLayout>
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:background="#FFA303"
        android:gravity="center"
        android:layout_height="130dp">
    
        <TextView
            android:layout_width="wrap_content"
            android:gravity="center"
            android:id="@+id/item_tv_explain"
            android:layout_height="wrap_content" />
    
        <TextView
            android:layout_width="wrap_content"
            android:gravity="center"
            android:id="@+id/item_tv_key"
            android:layout_height="wrap_content" />
    
        <TextView
            android:layout_width="wrap_content"
            android:gravity="center"
            android:id="@+id/item_tv_value"
            android:layout_height="wrap_content" />
    </LinearLayout>
    

    修改Adapter文件:

        ArrayList<RequestEntity> list_request;    //总的请求信息
    
        public MyAdapter(ArrayList<RequestEntity> list_request) {
            this.list_request = list_request;
        }
    
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View v;
    
            if(viewType == 1) {
                v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info1, parent, false);
            } else {
                v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_request_info2, parent, false);
            }
    
            ViewHolder viewHolder = new ViewHolder(v);
            return viewHolder;
        }
    
        @Override
        public int getItemViewType(int position) {
            // 瀑布流样式外部设置spanCount为2,在这列设置两个不同的item type,以区分不同的布局
            return position % 2;
        }
    
    
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.item_tv_explain.setText(list_request.get(position).explain);
            holder.item_tv_key.setText(list_request.get(position).key);
            holder.item_tv_value.setText(list_request.get(position).value);
        }
    
        @Override
        public int getItemCount() {
            return list_request == null ? 0 : list_request.size();
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder {
    
            TextView item_tv_explain;
            TextView item_tv_key;
            TextView item_tv_value;
    
            public ViewHolder(@NonNull View itemView) {
                super(itemView);
                item_tv_explain = itemView.findViewById(R.id.item_tv_explain);
                item_tv_key = itemView.findViewById(R.id.item_tv_key);
                item_tv_value = itemView.findViewById(R.id.item_tv_value);
            }
        }
    

    在MainActivity中设置

    // 初始化布局管理器
            StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL);
            // 设置布局管理器
            rv_request_details.setLayoutManager(mLayoutManager);
    

    截图:


    screen.png

    未完待续...

    相关文章

      网友评论

          本文标题:RecyclerView全解析

          本文链接:https://www.haomeiwen.com/subject/plkckctx.html