概述

针对RecyclerView,谷歌有一段介绍的话:
RecyclerView is a more advanced and flexible version of ListView. This widget is a Container for large sets of views that can be recycled and scrolled very efficiently. Use the RecyclerView widget when you have lists with elements that change dynamically.
大概就是说RecyclerView是一个更加高效灵活的ListView。当你有一系列的元素需要动态加载的时候,可以使用RecyclerView这个控件。
RecyclerView提供了高度自由化定制的功能,比如:
通过LayoutManager(布局管理器),控制item的显示方式;
通过ItemDecoration,控制item间的背景;
通过ItemAnimator,控制动态增删item的动画;

虽然RecyclerView提供了非常自由化的定制操作,但是它自身并不支持item的点击事件,也不像ListView一样能够简单的添加头和尾布局。想要实现这样的功能,同样需要自身去实现。

从上面我们可以看出使用RecyclerView的基本步骤:

  recyclerView = (RecyclerView) findViewById(R.id.recyclerView);  recyclerView.setLayoutManager();   //设置布局管理器  recyclerView.setAdapter();               //设置Adapter,同ListView  recyclerView.addItemDecoration();  //设置Item的间隔背景  recyclerView.setItemAnimator();      //设置Item增删时的动画

下面我将通过代码来逐步介绍RecyclerView的具体使用。

代码示例

1.布局文件content_main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <android.support.v7.widget.RecyclerView        android:id="@+id/recyclerView"        android:layout_width="match_parent"        android:layout_height="match_parent" />RelativeLayout>

2.Activity中的代码

package mo.yumf.com.mddemo;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {    private RecyclerView recyclerView;    private List mDatas;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.content_main);        initData();        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);        recyclerView.setLayoutManager(new LinearLayoutManager(this)); //设置布局管理器        recyclerView.setAdapter(new MyAdapter(this,mDatas));    //设置Adapter    }    private void initData() {        mDatas = new ArrayList<>();        for(int i = 0;i < 20;i ++){            mDatas.add("Test"+i);        }    }}

3.自定义Adapter

package mo.yumf.com.mddemo;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.List;public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{    private Context context;    private List mDatas;    public MyAdapter(Context context,List mDatas) {        this.context = context;        this.mDatas = mDatas;    }    @Override    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_recyclerview,parent,false));        return holder;    }    @Override    public void onBindViewHolder(MyViewHolder holder, int position) {        holder.textView.setText(mDatas.get(position));    }    @Override    public int getItemCount() {        return mDatas.size();    }    class MyViewHolder extends RecyclerView.ViewHolder {        TextView textView;        public MyViewHolder(View itemView) {            super(itemView);            textView = (TextView) itemView.findViewById(R.id.item_text);        }    }}

4.item的布局文件item_recyclerview.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="100dp"    android:background="#D1EEEE"    android:orientation="vertical">    <TextView        android:id="@+id/item_text"        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:layout_gravity="center_horizontal"        android:gravity="center"        android:text="Large Text"        android:textAppearance="?android:attr/textAppearanceLarge" />LinearLayout>

上述代码执行后效果图:
Android 中RecyclerView使用详解(一)_第1张图片

可以看到上面的Item之间没有分割线,给人感觉十分不友好,现在我们给它加上一个分割线背景。

添加分割线背景

文章开头的部分,我们提到过设置分割线是通过方法addItemDecoration(ItemDecoration decor)。但是通过查看代码能够知道ItemDecoration 类是一个抽象类:

public static abstract class ItemDecoration {    /**     * 该方法会在item view 的绘制之前调用     */    public void onDraw(Canvas c, RecyclerView parent, State state) {        onDraw(c, parent);    }    @Deprecated    public void onDraw(Canvas c, RecyclerView parent) {    }    /**     * 该方法会在item view 的绘制之后调用     */    public void onDrawOver(Canvas c, RecyclerView parent, State state) {        onDrawOver(c, parent);    }    @Deprecated    public void onDrawOver(Canvas c, RecyclerView parent) {    }    @Deprecated    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {        outRect.set(0, 0, 0, 0);    }    /**     *为每个item设置偏移量     */    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {        getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),parent);    }}

我们在继承该类来设置分割线时,需要用到的方法只有两个:
1.绘制分割线 public void onDraw(Canvas c, RecyclerView parent, State state);
2.设置偏移量 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state);

接下来我们看看具体是如何实现绘制分割线:

package mo.yumf.com.mddemo;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.support.v7.widget.RecyclerView.State;import android.view.View;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, State state) {            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);            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, View view, RecyclerView parent, State state) {            if (mOrientation == VERTICAL_LIST) {                    outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());            } else {                    outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);            }    }}

接着需要在原来的代码中添加:

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

修改之后,继续运行:
Android 中RecyclerView使用详解(一)_第2张图片

可以看到在执行addItemDecoration()之后,可以看到一条分割线。那么如果想要继续修改这天分割线的高度,背景色,需要怎么办呢?其实从上面的DividerItemDecoration类中,可以看到这条分割线的绘制是从android.R.attr.listDivider中读取的,所以我们在设置好这个类之后,可以再修改这个属性值来达到修改分割线的目的。如下:
系统主题设置:

<resources>        <style name="AppTheme" parent="Theme.AppCompat.Light">        -- Customize your theme here. -->        <item name="colorPrimary">@color/colorPrimary        "colorPrimaryDark">@color/colorPrimaryDark        "colorAccent">@color/colorAccent                "android:listDivider">@drawable/divider_bg    style>resources>

drawable/divider_bg.xml

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle">    <solid android:color="@android:color/white">solid>    <size android:height="6dp">size>shape>

运行代码,效果图:
Android 中RecyclerView使用详解(一)_第3张图片

好了,以上只是实现了类似ListView的布局效果,那么还有没有其他形式的布局效果呢,这就需要通过LayoutManager来实现了。

布局管理器(LayoutManager)

系统中LayoutManager是一个抽象类,他目前给我们提供了三个子类可以直接使用,如:
LinearLayoutManager:线性布局管理器,提供类似ListView的功能,如上;
GridLayoutManager:网格布局管理器;
StaggeredGridLayoutManager:瀑布流式布局管理器。

上面我们已经试过了LinearLayoutManager效果,现在我们可以继续使用GridLayoutManager效果,修改代码:

//     recyclerView.setLayoutManager(new LinearLayoutManager(this));        recyclerView.setLayoutManager(new GridLayoutManager(this,3));   //每一行的列数

还需要重新绘制分割线,之前的DividerItemDecoration类已经不能使用了,我们需要重新绘制分割线:

package mo.yumf.com.mddemo;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.GridLayoutManager;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.RecyclerView.State;import android.support.v7.widget.StaggeredGridLayoutManager;import android.view.View;public class DividerGridItemDecoration extends RecyclerView.ItemDecoration{    private static final int[] ATTRS = new int[]{ android.R.attr.listDivider };    private Drawable mDivider;    public DividerGridItemDecoration(Context context) {            final TypedArray a = context.obtainStyledAttributes(ATTRS);            mDivider = a.getDrawable(0);            a.recycle();    }    @Override    public void onDraw(Canvas c, RecyclerView parent, State state) {            drawHorizontal(c, parent);            drawVertical(c, parent);    }    public void drawVertical(Canvas c, RecyclerView parent) {            int childCount = parent.getChildCount();            for(int i = 0 ; i < childCount ; i ++){                View child = parent.getChildAt(i);                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();                int top = child.getTop() - params.topMargin;                int bottom = child.getBottom() + params.bottomMargin;                int left = child.getRight() + params.leftMargin;                int right = left + mDivider.getIntrinsicWidth();                mDivider.setBounds(left,top,right,bottom);                mDivider.draw(c);            }    }    public void drawHorizontal(Canvas c, RecyclerView parent) {            int childCount = parent.getChildCount();            for(int i = 0 ; i < childCount ; i ++){                View child = parent.getChildAt(i);                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();                int top = child.getBottom() + params.bottomMargin;                int bottom = top + mDivider.getIntrinsicHeight();                int left = child.getLeft() - params.leftMargin;                int right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth();                mDivider.setBounds(left,top,right,bottom);                mDivider.draw(c);            }    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {            int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();            int spanCount = getSpanCount(parent);            int childCount = parent.getAdapter().getItemCount();            if (isLastRaw(parent, itemPosition, spanCount, childCount)){  // 如果是最后一行,则不需要绘制底部                    outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);            } else if (isLastColum(parent, itemPosition, spanCount, childCount)){ // 如果是最后一列,则不需要绘制右边                    outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());            } else{                    outRect.set(0, 0, mDivider.getIntrinsicWidth(),mDivider.getIntrinsicHeight());            }    }    private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) {            RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();            if (layoutManager instanceof GridLayoutManager){                    if ((pos + 1) % spanCount == 0){  // 如果是最后一列,则不需要绘制右边                        return true;                    }            } else if (layoutManager instanceof StaggeredGridLayoutManager){                    int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();                    if (orientation == StaggeredGridLayoutManager.VERTICAL){                        //  // 如果是最后一列,则不需要绘制右边                    } else{                        childCount = childCount - childCount % spanCount;                        if (pos >= childCount){  // 如果是最后一列,则不需要绘制右边                            return true;                        }                    }            }            return false;    }    private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, int childCount) {            RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();            if (layoutManager instanceof GridLayoutManager) {                    childCount = childCount - childCount % spanCount;                    if (pos >= childCount)// 如果是最后一行,则不需要绘制底部                            return true;            } else if (layoutManager instanceof StaggeredGridLayoutManager){                    int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();                    // StaggeredGridLayoutManager 且纵向滚动                    if (orientation == StaggeredGridLayoutManager.VERTICAL){                            childCount = childCount - childCount % spanCount;                            // 如果是最后一行,则不需要绘制底部                            if (pos >= childCount)                                return true;                    } else{                            // StaggeredGridLayoutManager 且横向滚动,如果是最后一行,则不需要绘制底部                            if ((pos + 1) % spanCount == 0){                                return true;                            }                    }                }            return false;    }    private int getSpanCount(RecyclerView parent) {        // 列数        int spanCount = -1;        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();        if (layoutManager instanceof GridLayoutManager){                spanCount = ((GridLayoutManager) layoutManager).getSpanCount();        }else if (layoutManager instanceof StaggeredGridLayoutManager){                spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();        }        return spanCount;    }}

这个DividerGridItemDecoration类,非本人所写,借鉴自hongyang大神^-^!!。
然后,在修改一下divider_bg.xml中的宽度:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="rectangle">    <solid android:color="@android:color/white">solid>    <size android:height="6dp" android:width="6dp">size>shape>

执行后,效果图:
Android 中RecyclerView使用详解(一)_第4张图片

下面我们将继续使用StaggeredGridLayoutManager布局管理器,来实现瀑布流的效果。
1.设置布局管理器为StaggeredGridLayoutManager
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));
注:
在第二个参数为VERTICAL:前面的数字表示多少列;
在第二个参数为HORIZONTAL:前面的数字表示多少行;

2.设置item的分割线背景色,可以使用上面DividerGridItemDecoration类;
recyclerView.addItemDecoration(new DividerGridItemDecoration(this));

3.在Adapter中的onBindViewHolder方法里,为Item设置随机的高度。

......private List mHeights;......mHeights = new ArrayList();for (int i = 0; i < mDatas.size(); i++){    mHeights.add( (int) (100 + Math.random() * 300));}.....    @Override    public void onBindViewHolder(MyViewHolder holder, int position) {        ViewGroup.LayoutParams lp = holder.textView.getLayoutParams();        lp.height = mHeights.get(position);        holder.textView.setLayoutParams(lp);        holder.textView.setText(mDatas.get(position));    }.....

完成上述修改后,运行代码:
Android 中RecyclerView使用详解(一)_第5张图片

添加点击功能

前面我们说过recyclerView自身并不提供点击的接口回调,这需要我们自己实现。为了能够到达与传统的ListView相同的点击效果,我们可以在自定义的Adapter中,定义一个接口,通过该接口的方法可以将View以接口回调的方式传递出来。代码如下:

package mo.yumf.com.mddemo;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.ArrayList;import java.util.List;public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{    private Context context;    private List mDatas;    private List mHeights;    /** 定义接口*/    interface OnItemClickListener{        void onItemClick(View v,int position);    }    private OnItemClickListener onItemClickListener;    /** 对外提供方法,接收示例对象*/    public void setOnItemClickListener(OnItemClickListener onItemClickListener){        this.onItemClickListener = onItemClickListener;    }    public MyAdapter(Context context,List mDatas) {        this.context = context;        this.mDatas = mDatas;        mHeights = new ArrayList();        for (int i = 0; i < mDatas.size(); i++){            mHeights.add( (int) (100 + Math.random() * 300));        }    }    @Override    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_recyclerview,parent,false));        return holder;    }    @Override    public void onBindViewHolder(MyViewHolder holder, final int position) {        ViewGroup.LayoutParams lp = holder.textView.getLayoutParams();        lp.height = mHeights.get(position);        holder.textView.setLayoutParams(lp);        holder.textView.setText(mDatas.get(position));        if(onItemClickListener != null){            holder.textView.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    onItemClickListener.onItemClick(v,position); //使用接口回调的方法将参数传递出来                }            });        }    }    @Override    public int getItemCount() {        return mDatas.size();    }    class MyViewHolder extends RecyclerView.ViewHolder {        TextView textView;        public MyViewHolder(View itemView) {            super(itemView);            textView = (TextView) itemView.findViewById(R.id.item_text);        }    }}-------------------------------Activity中调用方法:MyAdapter adapter = new MyAdapter(this,mDatas);adapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {    @Override    public void onItemClick(View v,int position) {        Toast.makeText(getApplicationContext(),position +"=="+((TextView)v).getText(),Toast.LENGTH_SHORT).show();    }});

完成上述修改后,运行代码:
Android 中RecyclerView使用详解(一)_第6张图片

以上便是RecyclerView的基本使用,接下来将继续介绍RecyclerView的其他知识点。

参考博客:
http://blog.csdn.net/sanjay_f/article/details/48830311
http://blog.csdn.net/lmj623565791/article/details/45059587

更多相关文章

  1. android中colors.xml中用到的主要颜色的代码。
  2. android xml布局中TextView文字居中方法
  3. android 动态布局setLayoutParams方法设置
  4. android一种较为复杂的布局
  5. Android情景模式、文件管理器 完整示例编程详解、Android程序优
  6. 谈谈android不同尺寸,不同分辨率的布局
  7. Android 布局之GridLayout
  8. Android 的布局
  9. Android四种布局

随机推荐

  1. Android防止进程被第三方软件杀死
  2. Android UI - GridView长按实现拖拽效果
  3. Android 划出一个半透明的PopupWindow
  4. android 4.3源码编译
  5. 对android内置的sqlLite数据库进行增、删
  6. linux和android端的pthread学习
  7. Android与Webview交互
  8. android 同一个TextView不同文字的点击事
  9. Android listView 总是显示最后一项
  10. Android柱状图-柱子分组