首页 > 代码库 > RecyclerView的使用

RecyclerView的使用

  原文来自:http://www.cnblogs.com/liuling/p/2015-11-04-01.html

什么是RecyclerView
        RecyclerView是Android 5.0 materials design中的组件之一,相应的还有CardView、Palette等。看名字我们就能看出一点端倪,没错,它主要的特点就是复用。我们知道,Listview中的Adapter中可以实现ViewHolder的复用。RecyclerView提供了一个耦合度更低的方式来复用ViewHolder,RecyclerView只管回收与复用View,其他的你可以自己去设置,其高度解耦可以轻松的实现ListView、GridView以及瀑布流的效果
 
RecyclerView的用法        首先我们要gradle的依赖库中添加  
compile ‘com.android.support:recyclerview-v7:23.3.0‘
。如果是eclipse直接导入android-support-v7-recyclerview.jar就可以了。
技术分享

技术分享

技术分享

技术分享

找到v7下的包,编译的时候出错,可以更改为

技术分享

 

  • 控制其显示的方式,通过布局管理器LayoutManager
  • 控制Item间的间隔(可绘制),通过ItemDecoration
  • 控制Item增删的动画,通过ItemAnimator
  • 控制点击、长按事件,自己写
 
实例:
运用recyclerView实现listview的效果,并实现自定义监听,进行item的点击,长按事件
layout_recyclerview_item.xml:
注意:设置listview垂直滚动时,父布局的高度不能为mathch_parent ,不然会出现一个页面显示一条数据的现象,横向滚动同理.
<?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:layout_height="wrap_content">    <TextView        android:id="@+id/tv_text"        android:layout_width="match_parent"        android:layout_height="wrap_content" /></LinearLayout>

 

 
适配器的代码如下:
/** * Created by Administrator on 2016/9/27. */public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ItemViewHolder> {    private Context context;    private List<String>dataList;    private MyOnItemClickListener myOnItemClickListener;    /**     * 重写构造方法     * @param context 当前activity对象     * @param dataList 数据源     */    public MyRecyclerViewAdapter(Context context, List<String> dataList) {        this.context = context;        this.dataList = dataList;    }    /**     * 创建viewHolder     * @param parent     * @param viewType     * @return     */    @Override    public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        //加载布局        View view = LayoutInflater.from(context).inflate(R.layout.layout_recyclerview_item,parent,false);        //创建viewholder对象,将布局传入        ItemViewHolder viewHolder = new ItemViewHolder(view);        return viewHolder;    }    /**     * 绑定viewHolder     * @param holder  recycleView.ViewHolder的子类     * @param position 当前索引     */    @Override    public void onBindViewHolder(final ItemViewHolder holder,final int position) {        holder.tv_text.setText(dataList.get(position));        //给每个item设置点击事件        //判断是否存在监听
/** 这里加了判断,itemViewHolder.itemView.hasOnClickListeners() 目的是减少对象的创建,如果已经为view设置了click监听事件,就不用重复设置了,不然每次调用onBindViewHolder方法,都会创建两个监听事件对象,增加了内存的开销*/
        if(myOnItemClickListener != null&&!holder.tv_text.hasOnClickListeners()){            holder.tv_text.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    //注意:当点击该position的时候,recycleView中默认点击的是在父控件中的位置,当删除数据时,也是删除父布局中的对应索引的位置                    //比如:删除点击item4会删除Item4,再点击item6,会删除item7,因为item7在父布局中位置为6,因此推荐使用父类的position                    myOnItemClickListener.myOnItemClick(v,holder.getLayoutPosition());                }            });            holder.tv_text.setOnLongClickListener(new View.OnLongClickListener() {                @Override                public boolean onLongClick(View v) {                    myOnItemClickListener.myOItemLongClick(v,holder.getLayoutPosition());                    return true;                }            });        }    }    @Override    public int getItemCount() {        return dataList.size();    }    /**     * 设置自定义对外暴露的监听     * @param myOnItemClickListener     */    public void setMyOnItemClickListener(MyOnItemClickListener myOnItemClickListener){        this.myOnItemClickListener = myOnItemClickListener;    }    /**     * 删除数据     * @param position     */    public void deleteData(int position){        dataList.remove(position);        //更新当前删除条目的数据        notifyItemRemoved(position);    }    public void addData(int positon,String data){        dataList.add(positon,data);        //只更新当前插入的条目的数据        notifyItemInserted(positon);    }    /**     * 添加数据     * @param list     */    public void updateData(List<String> list){        dataList.addAll(list);        notifyDataSetChanged();    }    class ItemViewHolder extends RecyclerView.ViewHolder{        private TextView tv_text;        public ItemViewHolder(View itemView) {            super(itemView);            tv_text = (TextView) itemView.findViewById(R.id.tv_text);        }    }    public interface  MyOnItemClickListener{        void myOnItemClick(View view,int Postion);        void myOItemLongClick(View view,int position);    }}

可以看到数据适配器与BaseAdapter比较发生了相当大的变化,主要有3个方法:

 

getItemCount 这个不用说,获取总的条目数

onCreateViewHolder 创建ViewHolder

onBindViewHolder 将数据绑定至ViewHolder

可见,RecyclerView对ViewHolder也进行了一定的封装,但是如果你仔细观察,你会发出一个疑问,ListView里面有个getView返回View为Item的布局,那么这个Item的样子在哪控制?

其实是这样的,我们创建的ViewHolder必须继承RecyclerView.ViewHolder,这个RecyclerView.ViewHolder的构造时必须传入一个View,这个View相当于我们ListView getView中的convertView (即:我们需要inflate的item布局需要传入)。

还有一点,ListView中convertView是复用的,在RecyclerView中,是把ViewHolder作为缓存的单位了,然后convertView作为ViewHolder的成员变量保持在ViewHolder中,也就是说,假设没有屏幕显示10个条目,则会创建10个ViewHolder缓存起来,每次复用的是ViewHolder,所以他把getView这个方法变为了onCreateViewHolder。有兴趣的自己打印下Log,测试下

 

main方法:

public class MainActivity extends AppCompatActivity {    private RecyclerView recyclerView;    private List<String> dataList = new ArrayList<String>();    private MyRecyclerViewAdapter recyclerViewAdapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //初始化控件        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);        /**            设置布局管理器,listview风格则设置为LinearLayoutManager            gridview风格则设置为GridLayoutManager            pu瀑布流风格的设置为StaggeredGridLayoutManager                */        //默认竖直滚动        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);        recyclerView.setLayoutManager(linearLayoutManager);        //初始化数据        initData();        //创建适配器        recyclerViewAdapter = new MyRecyclerViewAdapter(this,dataList);        //设置适配器        recyclerView.setAdapter(recyclerViewAdapter);        //设置自定义点击监听        recyclerViewAdapter.setMyOnItemClickListener(new MyRecyclerViewAdapter.MyOnItemClickListener() {            //点击item的时候调用            @Override            public void myOnItemClick(View view, int Postion) {                Toast.makeText(MainActivity.this, dataList.get(Postion), Toast.LENGTH_SHORT).show();                recyclerViewAdapter.deleteData(Postion);            }            //长按item的时候调用            @Override            public void myOItemLongClick(View view, int position) {                Toast.makeText(MainActivity.this,"长按--"+dataList.get(position), Toast.LENGTH_SHORT).show();                recyclerViewAdapter.addData(position,"我是新来的");            }        });    }    private void initData() {        for (int i = 0; i < 30; i++) {            dataList.add((i+1)+"条数据");        }    }}

效果如下:

点击时:

技术分享

点击后:

技术分享

 长按后:

 技术分享

ItemDecoration

我们可以通过该方法添加分割线: 
mRecyclerView.addItemDecoration() 

RecyclerView.ItemDecoration的实现类

package fanggao.qf.recycleviewlistview;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.View;/** * Created by Administrator on 2016/9/27. */public class DividerItemDecoration extends RecyclerView.ItemDecoration {    private static final int[] ATTRS = new int[]{            android.R.attr.listDivider    };    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;    private Drawable mDivider;    private int mOrientation;    public DividerItemDecoration(Context context, int orientation) {        final TypedArray a = context.obtainStyledAttributes(ATTRS);        mDivider = a.getDrawable(0);        a.recycle();        setOrientation(orientation);    }    public void setOrientation(int orientation) {        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {            throw new IllegalArgumentException("invalid orientation");        }        mOrientation = orientation;    }    @Override    public void onDraw(Canvas c, RecyclerView parent) {        Log.v("recyclerview - itemdecoration", "onDraw()");        if (mOrientation == VERTICAL_LIST) {            drawVertical(c, parent);        } else {            drawHorizontal(c, parent);        }    }    public void drawVertical(Canvas c, RecyclerView parent) {        final int left = parent.getPaddingLeft();        final int right = parent.getWidth() - parent.getPaddingRight();        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            final View child = parent.getChildAt(i);            android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int top = child.getBottom() + params.bottomMargin;            final int bottom = top + mDivider.getIntrinsicHeight();            mDivider.setBounds(left, top, right, bottom);            mDivider.draw(c);        }    }    public void drawHorizontal(Canvas c, RecyclerView parent) {        final int top = parent.getPaddingTop();        final int bottom = parent.getHeight() - parent.getPaddingBottom();        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            final View child = parent.getChildAt(i);            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int left = child.getRight() + params.rightMargin;            final int right = left + mDivider.getIntrinsicHeight();            mDivider.setBounds(left, top, right, bottom);            mDivider.draw(c);        }    }    @Override    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {        if (mOrientation == VERTICAL_LIST) {            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());        } else {            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);        }    }}

该实现类可以看到通过读取系统主题中的 Android.R.attr.listDivider作为Item间的分割线,并且支持横向和纵向

在源代码上添加一句

 recyclerView.addItemDecoration(new DividerItemDecoration(this,                DividerItemDecoration.VERTICAL_LIST));

效果:

技术分享

该分割线是系统默认的,你可以在theme.xml中找到该属性的使用情况

具体见转载请标明出处: 
http://blog.csdn.net/lmj623565791/article/details/45059587; 
本文出自:【张鸿洋的博客】

RecyclerView的使用