Android学习笔记之RecyclerView详解

Android学习笔记之RecyclerView详解

  1. RecyclerView是什么?

      在android5.0,开始出现了一些新特性,其中就包括了非常受欢迎的RecyclerView。RecyclerView是一种新的视图组,其目的是为任何基于适配器的视图提供相似的渲染方式。该控件用于在有限的窗口中展示大量数据集,它被作为ListView和GirdView控件的继承者。RecyclerView高度接耦,异常的灵活,通过设置不同的LayoutManager,ItemDecoration,ItemAnimator来实现令人想象不到的效果。

2.RecyclerView的用法:
  
  自从RecyclerView的出现,慢慢的ListView 和 GridView开始要面向淘汰的边缘了。因为RecyclerView不仅仅能替代ListView和GridView,而且还具有很多你想象不到的效果,那么具体的效果,下面开始慢慢的介绍吧,先看看他的一些基本用法。

  • Datas : 要显示的数据

  • Adapter:适配器,绑定数据集

  • ViewHolder:根据当前的数据保存视图

  • LayoutManager:布局管理器,决定item如何摆放

  • ItemDecoration:对item的装饰,美化item,

  • ItemAnimator:动画(当item被增加、删除、重新摆放时才有效)

  • Listener:事件,对于事件,RecyclerView本身不提供,只得自己去实现

对于RecyclerView我们现在要掌握的主要就是他的三种管理形式:

2.1 LinearLayoutManager

线性布局,LayoutManager的实现类,类似于实现ListView的风格,一般
ListView只有垂直的方向,而这里可包含两种类型,Vertical和Horizontal

2.2 GridLayoutManager

格子布局、继承自LinearLayoutManager,实现效果类似GridView

2.3 StaggeredGridLayoutManager

交错的格子布局、同样也是LayoutManager的实现类,类型包括Vertical和Horizontal,与GridLayoutManager很相似,不过是交错的格子,也就是宽高不等的格子视图、类似瀑布流的效果。

其次,我们需要掌握他的一些点击和长按事件,对于RecyclerView其本身没有给我们提供这些事件监听,所以,对于这些事件,我们还得自己去实现。
 
3. 首先先看看类似于ListView的布局实现。

基本步奏:(由于这是新特性包中给我们提供的,所以我们需要先导入RecyclerView依赖包)
在build.gradle中添加如下一句代码,记住,是对应module下面的build.gradle,不是project下的build.gradle

dependencies {
    .....
    //添加此依赖
    compile 'com.android.support:recyclerview-v7:24.2.1'
}

3.1 在布局文件中添加RecyclerView控件

3.2 创建item的子布局,和ListView一样,需要有一个item对应的子布局

3.3 创建适配器

3.4 创建并设置对应的布局管理器

3.5 设置Adapter适配器

具体代码实现如下:

activity_main_list.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/mRecyclerList"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
RelativeLayout>

recycler_item.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:gravity="center"
    android:background="@color/colorAccent"
    android:padding="15dp">

    <TextView
        android:id="@+id/mItem"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        android:gravity="center" />
LinearLayout>

这里我们需要注意一下布局中的几个参数的区别,在ListView中,(假如也是使用上面的布局)不管你对layout_width 和layout_height设置为wrap_content也好还是match_parent,对item的高度都不会有什么影响,因为ListView会对你的item布局进行管理,所以你设置的高宽会无效,但是如果在RecyclerView中,设置对应的item高宽度的话,那么是会有影响的,因为RecyclerView不会去管理你的item布局,它只会按你设置的具体情况来显示。假如,你设置layout_height为match_parent,那么最后的显示效果是,你的整个一个界面中就只有一个布局item。也就是说这个item布局会占满整个屏幕。

创建自定义的适配器

MyRecylerAdapter.java

public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {
    //数据源
    private List mData;
    //上下文
    private Context mContext;
    //布局解析器
    private LayoutInflater mInflater;
    public MyRecyclerAdapter(Context context, List data){
        mContext = context;
        mData = data;
        mInflater = LayoutInflater.from(mContext);
    }
    //创建ViewHolder,相当于ListView Adapter的getView方法
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = mInflater.inflate(R.layout.recycler_item,parent,false);
        return new ViewHolder(itemView);
    }
    //数据绑定
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.mText.setText(mData.get(position));
    }

    //数据的长度
    @Override
    public int getItemCount() {
        return mData == null ? 0 : mData.size();
    }

    //ViewHolder,需要继承RecyclerView.ViewHolder
    public static class ViewHolder extends RecyclerView.ViewHolder{
        private TextView mText;
        public ViewHolder(View itemView) {
            super(itemView);
            mText = (TextView)itemView.findViewById(R.id.mItem);
        }
    }
}

创建并设置对应的布局管理器和适配器

public class MainActivityRecyclerViewList extends AppCompatActivity {
    private RecyclerView mRecycler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_list);
        //查找控件ID
        mRecycler = (RecyclerView)findViewById(R.id.mRecyclerList);
        //创建布局管理器
        LinearLayoutManager manager = new LinearLayoutManager(this);
        //设置布局管理器,默认item方向为垂直
        mRecycler.setLayoutManager(manager);
        //创建适配器
        MyRecyclerAdapter adapter = new MyRecyclerAdapter(this, getData());
        //设置适配器
        mRecycler.setAdapter(adapter);
    }
    //设置数据源
    public List getData() {
        List data = new ArrayList<>();
        for(int i = 0; i < 50; i++){
            data.add("这是第" + String.format("%2d",i) + "个item");
        }
        return data;
    }
}

显示效果如下:

Android学习笔记之RecyclerView详解_第1张图片

很明显,这中效果你会发现看起来很遍扭,因为没有分割线,所以看起来有点怪怪的,那么我们是不是可以像ListView一样可以在布局中通过设置divider和dividerHeight属性来设置分割线呢?答案是no,不行的,在RecyclerView的布局中,根本没有提供这样的属性给你。即使你去设置了,也是没有效果的,那要怎样才能设置分割线呢,在RecyclerView中,他为我们提供了一个方法。可以让我们自己来绘制分割线。通过mRecycler.addItemDecoration(ItemDecoration decor)方法,可以让我们设置分割线。

先来看看这个方法的参数,该方法的参数为RecyclerView.ItemDecoration,该类为抽象类,官方目前并没有提供默认的实现类。所以只有自己去实现了,先看看这个抽象类的主要的三个方法吧

//在itemView绘制完之前调用,也就是说此方法draw出来的效果会在itemView的下面
 @Override
 public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
      super.onDraw(c, parent, state);
  }
//与onDraw相反,draw出来的效果将叠加在itemView的上面
  @Override
  public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
      super.onDrawOver(c, parent, state);
  }
//通过配置outRect来设置itemView的insert边界,相当于itemView的margin
  @Override
  public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
                super.getItemOffsets(outRect, view, parent, state);
  }

通过上面的方法,其实我们只需要在getItemOffsets方法中设置边界就可以实现分割线了。在MainActivityRecyclerViewList.java中添加这样的代码。

mRecycler.addItemDecoration(new RecyclerView.ItemDecoration() {
            @Override
            public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
                super.onDraw(c, parent, state);
                //绘制边界的颜色,为绿色
                c.drawColor(Color.GREEN);
            }

            @Override
            public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
                super.onDrawOver(c, parent, state);
            }

            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
                super.getItemOffsets(outRect, view, parent, state);
                //绘制边界的高度
                outRect.offset(0,5);
            }
        });

看看实现效果:

Android学习笔记之RecyclerView详解_第2张图片

乍一看,貌似效果还行,有分割线了。但是你会发现分割线应该是处在两个item的中间位置,最上面和最下面竟然也显示了一条分割线(这里没有贴上最下面的item的分割线效果图,你可以自己去实现,然后看效果,最下面也会有一条分割线),那么如何去掉最上面和最下面的分割线呢,很简单,我们只需要在里面判断一下如果是第一个item,我们就不绘制边界,如果是最后一个Item我们也不绘制边界,这样就可以达到真正的分割线效果了。

 @Override
 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
   super.getItemOffsets(outRect, view, parent, state);
   //判断,如果不为第一个item 和最后一个item就进行绘制边界线。
   if (parent.getChildAdapterPosition(view) == 0 ||parent.getChildAdapterPosition(view) == mTotalSize - 1) 
   {
        return;
   }
    outRect.offset(0,5);
  }

效果图如下:

Android学习笔记之RecyclerView详解_第3张图片

和上面的对比一下,你会发现最上面没有了那条边界线。不过使用这样的布局也只是随便玩。并不能实现一些特定的效果,我们可以使用如下代码来实现分割线。下面的代码我就不做解释了,我也是从git上copy来的开源地址。下面的代码很好的实现了分割线,包括水平和垂直,都能设置,只需要自己指定即可。

public class DividerListItemDecoration extends RecyclerView.ItemDecoration {
        public class DividerListItemDecoration 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 DividerListItemDecoration(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) {
            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);
            }
        }
    }
}

这样我们只需要在MainActivityRecyclerViewList修改此语句即可。

 //设置垂直方向的分割线
        mRecycler.addItemDecoration(new DividerListItemDecoration(this, DividerListItemDecoration .VERTICAL_LIST ));

这样就很方便的实现了分割线效果。

效果图如下:

Android学习笔记之RecyclerView详解_第4张图片

该分割线是系统默认的,你可以在theme.xml中找到该属性的使用情况。那么,使用系统的listDivider有什么好处呢?就是方便我们去随意的改变分割线的风格,该属性我们可以直接声明在styles下:

<resources>
    
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary
        "colorPrimaryDark">@color/colorPrimaryDark
        "colorAccent">@color/colorAccent
        
        "android:listDivider">@drawable/divider_line
    style>
resources>

然后自己写一个drawable风格,更换一条分割线,根据自己的需求随意画,随便玩。 divider_line.xml


<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <size android:height="5dp" android:width="5dp"/>
    <gradient
        android:endColor="@color/colorPrimaryDark"
        android:startColor="@color/colorGreen" />
shape>

效果图如下:

Android学习笔记之RecyclerView详解_第5张图片

 
4. 实现类似与GridView的实现效果

MainActivityRecyclerViewGrid .java

public class MainActivityRecyclerViewGrid extends AppCompatActivity {
    private RecyclerView mRecycler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_list);
        mRecycler = (RecyclerView)findViewById(R.id.mRecyclerList);
        //创建GridLayoutManager,这里创建一个4列的GridView效果
        GridLayoutManager layout = new GridLayoutManager(this, 4);
        //设置布局
        mRecycler.setLayoutManager(layout);
        //设置分割线
        mRecycler.addItemDecoration(new DividerGridItemDecoration(this));
        mRecycler.setAdapter(new MyRecyclerAdapter(this,getData()));
    }

    public List getData() {
        List data = new ArrayList<>();
        for(int i = 0; i < 100; i++){
            data.add("这是第" + String.format("%2d",i) + "个item");
        }
        return data;
    }
}

只需要修改LayoutManager即可,就可以实现我们的布局了。其他的布局不需要改,只需要修改的是实现分割线的类。对于分割线,前面的DividerListItemDecoration就不适用了,主要是因为它在绘制的时候,比如水平线,针对每个child的取值为:

final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();

因为每个Item一行,这样是没问题的。而GridLayoutManager时,一行有多个childItem,这样就多次绘制了,并且GridLayoutManager时,Item如果为最后一列(则右边无间隔线)或者为最后一行(底部无分割线)。

因此修改后的DividerGridItemDecoration.java如下(此代码参考了鸿洋大神的代码)

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, RecyclerView.State state)
    {

        drawHorizontal(c, parent);
        drawVertical(c, parent);

    }

    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;
    }

    public void drawHorizontal(Canvas c, RecyclerView parent)
    {
        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.getLeft() - params.leftMargin;
            final int right = child.getRight() + params.rightMargin
                    + mDivider.getIntrinsicWidth();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent)
    {
        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.getTop() - params.topMargin;
            final int bottom = child.getBottom() + params.bottomMargin;
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicWidth();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    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)
            {
                if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
                {
                    return true;
                }
            } 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;
    }

    @Override
    public void getItemOffsets(Rect outRect, int itemPosition,
                               RecyclerView parent)
    {
        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());
        }
    }
}

主要在getItemOffsets方法中,去判断如果是最后一行,则不需要绘制底部;如果是最后一列,则不需要绘制右边,整个判断也考虑到了StaggeredGridLayoutManager的横向和纵向,所以稍稍有些复杂。最重要还是去理解,如何绘制什么的不重要。一般如果仅仅是希望有空隙,还是去设置item的margin方便。

效果图如下:

Android学习笔记之RecyclerView详解_第6张图片

Ok,GirdView的基本布局也已经实现了。
  
  
5. 最后来设置一下重头戏了,瀑布流布局,同样我们只需要修改一行代码即可,修改布局管理器即可。

mRecycler.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));

这里需要注意的是,如果第二个参数是StaggeredGridLayoutManager.VERTICAL,表示设置3列。

如果第二个参数是StaggeredGridLayoutManager.HORIZONTAL,表示设置3行

看看3列的效果图:

Android学习笔记之RecyclerView详解_第7张图片

是不是有点类似于瀑布流的效果呢。

然后设置为3行看看效果

mRecycler.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.HORIZONTAL));

效果图如下:

Android学习笔记之RecyclerView详解_第8张图片

效果有点不明显,并且效果不太好。主要是,这个高度是wrap_content,自适应而已。为了实现瀑布流效果,我们可以在适配器的onBindViewHolder方法中为我们的item设置个随机的高度,

//数据绑定
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.mText.setText(mData.get(position));
        holder.mText.setHeight(new Random().nextInt(300));
        holder.mText.setWidth(new Random().nextInt(300));
    }

效果图如下:

Android学习笔记之RecyclerView详解_第9张图片

差不多效果就实现了。。可能有点不美观,但是,具体的大家可以自己去调整高度和宽度,然后去实现瀑布流的效果。

  1. 实现点击事件

对于点击事件,RecyclerView并没有为我们提供,所以还得我们自己去实现了。具体实现都在MyRecyclerAdapter里面

public class MyRecyclerAdapter extends RecyclerView.Adapter implements View.OnClickListener {
    //数据源
    private List mData;
    //上下文
    private Context mContext;
    //布局解析器
    private LayoutInflater mInflater;

    //监听事件
    private OnItemClickListener mListener;

    //当前的RecyclerView布局
    private RecyclerView mRecyclerView;
    public MyRecyclerAdapter(Context context, List data){
        mContext = context;
        mData = data;
        mInflater = LayoutInflater.from(mContext);
    }
    //创建ViewHolder,相当于ListView Adapter的getView方法
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = mInflater.inflate(R.layout.recycler_item,parent,false);
        itemView.setOnClickListener(this);
        return new ViewHolder(itemView);
    }

    //解除当前关联的布局
    @Override
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);
        mRecyclerView = null;
    }
    //关联当前的RecyclerView布局
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        mRecyclerView = recyclerView;
    }
    //给外界提供一个设置item点击事件
    public void setOnItemClickListener(OnItemClickListener listener){
        mListener = listener;
    }

    //点击事件
    @Override
    public void onClick(View v) {
        if(mListener != null){
            int position = mRecyclerView.getChildAdapterPosition(v);
            mListener.onItemClickListener(mRecyclerView,v,position,getItemId(position),mData.get(position));
        }
    }

    //自定义的事件接口,通过接口回调就可以很好的实现点击事件了
    public interface OnItemClickListener{
        void onItemClickListener(RecyclerView parent, View view, int position, long id,String data);
    }
    //增加一个添加数据的方法
    public void addData(int position, String data){
        mData.add(position,data);
        notifyItemInserted(position);
    }
    //移除数据
    public void removeData(int position){
        mData.remove(position);
        notifyItemRemoved(position);
    }
    //数据绑定
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.mText.setText(mData.get(position));
        holder.mText.setHeight(new Random().nextInt(300));
        holder.mText.setWidth(new Random().nextInt(300));
    }

    //数据的长度
    @Override
    public int getItemCount() {
        return mData == null ? 0 : mData.size();
    }

    //ViewHolder,需要继承RecyclerView.ViewHolder
    public static class ViewHolder extends RecyclerView.ViewHolder{
        private TextView mText;
        public ViewHolder(View itemView) {
            super(itemView);
            mText = (TextView)itemView.findViewById(R.id.mItem);
        }
    }
}

MainActivityRecyclerViewStaggered .java

public class MainActivityRecyclerViewStaggered extends AppCompatActivity implements MyRecyclerAdapter.OnItemClickListener {
    private RecyclerView mRecycler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_list);
        mRecycler = (RecyclerView)findViewById(R.id.mRecyclerList);
        mRecycler.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));
        mRecycler.addItemDecoration(new DividerGridItemDecoration(this));
        MyRecyclerAdapter adapter = new MyRecyclerAdapter(this, getData());
        //设置监听事件
        adapter.setOnItemClickListener(this);
        mRecycler.setAdapter(adapter);
    }
    public List getData() {
        List data = new ArrayList<>();
        for(int i = 0; i < 100; i++){
            data.add("这是第" + String.format("%2d",i) + "个item");
        }
        return data;
    }

    //当我们点击某个item的时候,就删除当前点击的item,这里只是为了实现点击的效果,具体的功能大家可以
    //自己去实现
    @Override
    public void onItemClickListener(RecyclerView parent, View view, int position, long id, String data) {
        Toast.makeText(this,data + "已删除",Toast.LENGTH_SHORT).show();
        parent.removeView(view);
    }
}

效果图如下:

Android学习笔记之RecyclerView详解_第10张图片

需要注意的是,在MyRecyclerAdapter中,更新数据集不是用notifyDataSetChanged()而是
notifyItemInserted(position)与notifyItemRemoved(position) 。notifyDataSetChanged()这个参数在RecyclerView中基本已经废弃了。
  
  
7. 有关动画的设置,这里我就不做过多的讲解了。

ItemAnimator

1.继承RecyclerView.ItemAnimator

2.提供默认的Animator:DefaultItemAnimator

  
  
8. notifyDataChange

notifyDataSetChanged()弃用

notifyItemChanged(int position)

notifyItemInserted(int position)

notifyItemMoved(int fromPositon,int toPosition)

notifyItemRemoved(int position)

//range系列,多个item的操作

notifyItemRangeChanged(int positionStart,int itemCount)

notifyItemRangeinserted(int posiontStart,int itemCount)

notifyItemRangeRemoved(int positionStart,int itemCount)

参考资源->鸿洋

你可能感兴趣的:(Design)