RecyclerView最全讲解

概述

RecyclerView出现在Android 5中 需要引进support-v7包内

构成

一个RecyclerView由六个成分

  • Adapter:提供数据,为每个Item创建视图(相似于ListView)
  • ItemAnimator:负责添加、移动、移除的动画效果
  • ItemDecoration:为每个Item视图添加子视图(e.g. 添加分割线)
  • LayoutManager:负责Item视图的布局管理器(一个线性布局,类似于ListView;一个网格布局;一个瀑布流式布局)
  • ViewHolder:承载Item视图的子视图
  • RecyclerView本身:一起绑定任何事务

展示一个RecyclerView

准备你的project

  • 如果你使用Gradle,添加你的dependenciescompile 'com.android.support:recyclerview-v7:25.1.0'
  • 使用CardView 同样添加依赖
    compile 'com.android.support:cardview-v7:25.1.0'

Adapter

  • 第一步:声明ViewHolder 类,它必须继承 RecyclerView.ViewHolder ,在这里有两个TextView(ViewHolder不了解,阅读Hold View Objects in a View Holder)
public static class ViewHolder extends RecyclerView.ViewHolder {
        TextView title;
        TextView subtitle;

        public ViewHolder(View itemView) {
            super(itemView);

            title = (TextView) itemView.findViewById(R.id.title);
            subtitle = (TextView) itemView.findViewById(R.id.subtitle);
        }
    }
  • 第二步:Adapter负责扮演两个角色,不仅为底部数据提供支持而且还负责为数据创建合适的视图。
    • 继承RecyclerView.Adapter需要实现以下三个方法
      • public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType):创建一个视图然后返回一个正在匹配的ViewHolder
      • public void onBindViewHolder(ViewHolder holder,int position): 绑定View,根据返回的position类型,从而进行绑定到ViewHolder
      • public int getItemCount():返回View中Item的个数
    • 有需求才实现的方法
      • public int getItemViewType(int position) :判断item的类型,从而绑定不同的view
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private List mDatas;

    public MyAdapter(List list) {
        this.mDatas = list;
    }
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View layout = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
        return new ListHolder(layout);
    }
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ((ListHolder) holder).tv.setText(mDatas.get(position));
    }
    @Override
    public int getItemCount() {
        return mDatas.size();

    }
    class ListHolder extends RecyclerView.ViewHolder {
        TextView tv;
        public ListHolder(View itemView) {
            super(itemView);
            tv = (TextView) itemView.findViewById(R.id.item);
        }
    }
}

RecyclerView.LayoutManager

  • LinearLayoutManager提供了横向和竖向两种布局。默认是LinearLayout.VERTICAL
  • LinearLayoutManager提供以下几个方法获取屏幕上的顶部item和底部item
    • findFirstVisibleItemPosition()
    • findFirstCompletelyVisibleItemPosition()
    • findLastVisibleItemPosition()
    • findLastCompletelyVisibleItemPosition()

RecyclerView.ItemDecoration

通过ItemDecoration可以使各个Item在视觉上相互分开,其实和ListView的Divider很像。ItemDecoration并不是RecyclerView必须设置的,开发者可以不设置或者设置多个Decoration。RecyclerView会遍历所有的ItemDecoration并调用各自的绘图方法。
继承RecyclerView.ItemDecoration需要实现以下方法:

  • public void onDraw(Canvas c,RecyclerView parent,RecyclerView.State state)
  • public void getItemOffset(Rect outRect,int itemPosition,RecyclerView parent):调用getItemOffset方法来计算每个Item的Decoration合适的尺寸。

RecyclerView.ItemAnimator

当Item有以下三种操作时RecyclerView所提供的动画效果:删除添加移动
Google提供了一个名为DefaultItemAnimator的默认ItemAnimator供开发者使用。如果开发者不为RecyclerView设置ItemAnimator,RecyclerView也会使用默认的DefaultItemAnimator。
显然,为了让动画效果起效,开发者必须通知Adapter数据有改变。之前我们使用Adapter时会调用notifyDataSetChanged()来通知Adapter数据改变并更新视图,现在RecyclerView,Adapter提供了许多notifyItemXXX()方法:

  • notifyItemChanged(int position)
  • notifyItemInserted(int position)
  • notifyItemRemoved(int position)
  • notifyItemMoved(int fromPosition, int toPosition)
  • notifyItemRangeChanged(int positionStart, int itemCount)
  • notifyItemRangeInserted(int positionStart, int itemCount)
  • notifyItemRangeRemoved(int positionStart, int itemCount)
  • notifyDataSetChanged()

使用RecyclerView

  • 第一步:添加RecyclerView在Activity的布局上
"http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    .support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
  • 第二步
    • mRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));//设置布局
    • mRecyclerView.setItemAnimator(new DefaultItemAnimator());//设置动画(非必需)
    • mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));//设置分割线(非必需)
    • mRecyclerView.setAdapter(mAdapter = new MyAdapter(mDatas));//设置Adapter
public class demo2 extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private MyAdapter mMyAdapter;
    private List mList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo2);

        //RecyclerView三部曲+LayoutManager
        mRecyclerView = (RecyclerView)findViewById(R.id.rv_demo2);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(linearLayoutManager);
        initData();
        mMyAdapter = new MyAdapter(mList);
        mRecyclerView.setAdapter(mMyAdapter);
    }
    //初始化RecyclerView中每个item的数据
    private void initData(){
        mList = new ArrayList();
        for (int i = 0; i < 20; i++){
            mList.add("item" + i);
        }
    }

附加功能

添加点击事件

第一种(在Adapter内添加)

    public interface OnItemClickListener{
        void onItemClick(View view, int position);
    }

    public interface OnItemLongClickListener{
        void onItemLongClick(View view, int position);
    }
    private OnItemClickListener mOnItemClickListener;
    private OnItemLongClickListener mOnItemLongClickListener;

//设置Item点击监听
    public void setOnItemClickListener(OnItemClickListener mOnItemClickListener){
        this.mOnItemClickListener = mOnItemClickListener;
    }

    public void setOnItemLongClickListener(OnItemLongClickListener mOnItemLongClickListener) {
        this.mOnItemLongClickListener = mOnItemLongClickListener;
    }

    public MyAdapter(List data) {
        this.mDatas = data;
    }

    //创建Item视图,并返回相应的ViewHolder
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        MyViewHolder myViewHolder = new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_single_textview,parent,false));
        return myViewHolder;
    }

    //绑定数据到正确的Item视图上
    @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {

        holder.textView.setText(mDatas.get(position));
        // 如果设置了回调,则设置点击事件
        if (mOnItemClickListener != null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = holder.getLayoutPosition();
                    mOnItemClickListener.onItemClick(holder.itemView,position);
                }
            });
        }
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener()
            {
                @Override
                public boolean onLongClick(View v)
                {
                    int position = holder.getLayoutPosition();
                    mOnItemLongClickListener.onItemLongClick(holder.itemView,position);
                    //返回true 表示消耗了事件 事件不会继续传递
                    return true;
                }
            });
        }

第二种(在ViewHolder内和在Activity内)

  • ViewHolder应用View.OnClickListenerView.OnLongClickListener
public class Adapter extends SelectableAdapter<Adapter.ViewHolder> {
    // …

    private ViewHolder.ClickListener clickListener;

    public Adapter(ViewHolder.ClickListener clickListener) {
        super();

        this.clickListener = clickListener;
    }

/**
*     public void setOnItemClickListener(MyItemClickListener listener){  
        this.mItemClickListener = listener;  
    }  
* 有此方法 Activity中onCreate内需要初始化下面已给出
**/
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final int layout = viewType == TYPE_INACTIVE ? R.layout.item : R.layout.item_active;

        View v = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
        return new ViewHolder(v, clickListener);
    }

    // …

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,
            View.OnLongClickListener {

        TextView title;
        TextView subtitle;
        View selectedOverlay;

        private ClickListener listener;

        public ViewHolder(View itemView, ClickListener listener) {
            super(itemView);

            title = (TextView) itemView.findViewById(R.id.title);
            subtitle = (TextView) itemView.findViewById(R.id.subtitle);
            selectedOverlay = itemView.findViewById(R.id.selected_overlay);

            this.listener = listener;

            itemView.setOnClickListener(this);
            itemView.setOnLongClickListener(this);
        }

        @Override
        public void onClick(View v) {
            if (listener != null) {
                listener.onItemClicked(getPosition());
            }
        }

        @Override
        public boolean onLongClick(View v) {
            if (listener != null) {
                return listener.onItemLongClicked(getPosition());
            }

            return false;
        }

        public interface ClickListener {
            public void onItemClicked(int position);
            public boolean onItemLongClicked(int position);
        }
    }
}
  • Activity内(继承ViewHolderClickListener)
    • 初始化 (onCreate内)
      • this.mAdapter.setOnItemClickListener(this);
      • this.mAdapter.setOnItemLongClickListener(this);
@Override  
    public void onItemClick(View view, int postion) {  
        MyItemBean bean = mData.get(postion);  
        if(bean != null){  
            Toast.makeText(this, bean.tv, Toast.LENGTH_SHORT).show();  
        }  
    }  

    @Override  
    public void onItemLongClick(View view, int postion) {  
        MyItemBean bean = mData.get(postion);  
        if(bean != null){  
            Toast.makeText(this, "LongClick "+bean.tv, Toast.LENGTH_SHORT).show();  
        }  
    }  

添加Header和Footer

=========================更新中

Github地址

资料来源

RecyclerView basics
Android RecyclerView 使用完全解析 体验艺术般的控件
Android-RecylerView初识

你可能感兴趣的:(Android学习笔记)