Android 开发之RecyclerView的使用

Android 开发之RecyclerView的使用

本篇博客主要参考 鸿洋大神的文章进行编写,如有意见,请告知,原博客地址:(http://blog.csdn.net/lmj623565791/article/details/45059587)

充分利用时间,总结最近一直在研究的一个很实用的控件,以做如下分享:

自android 5.0后,谷歌推出了RecyclerView控件,那么我接下来从它的定义、优点、使用方法及简单拓展进行总结,意在使更多的开发替换ListView,如有错误与误导性语言和表达,请留言指出。

  • RecyclerView 的定义
  • RecyclerView 与 ListView 相比较的优点
  • RecyclerView 的简单使用
  • RecyclerView 的Adapter使用
  • RecyclerView 增加分隔线以及修改分隔线样式
  • RecyclerView 的条目点击事件
  • RecyclerView 结合MaterialRefreshLayout 构成流畅而优雅的刷新和加载更多

1.RecyclerView 定义

该控件是support-7包里的新控件,是一个强大的滑动控件,根据官方的介绍翻译:该控件用于在有限的显示窗口展示大量的数据集,所以其本质原理和ListView是相类似的,从它的名字也不难判断出,其实现原理肯定涉及复用问题,那已经有了ListView为什么还要更推崇RecyclerView呢?这就推及到第二个问题了。

2.RecyclerView 与 ListView 的比较

通过使用RecyclerView控件,我们可以在APP中创建带有Material Design风格的复杂列表。既然官方推荐使用,那肯定存在着较ListView过人之处,现在就RecyclerView的优点进行罗列:

  • (1) RecylerView 对于原有的ViewHolder回收复用功能进行了封装,也就是说RecylerView标准化了ViewHolder,编写Adapter时面向的是ViewHolder而不再是View,复用的逻辑被封装了,写起来更加简单
  • (2) 其拥有强大的可扩展性,高度的解耦,异常的灵活的特性。例如:你想控制横向或者纵向滑动列表效果可以通过LinearLayoutManager这个类来进行控制(与GridView效果对应的是GridLayoutManager,与瀑布流对应的还有StaggeredGridLayoutManager等),也就是说RecylerView不再拘泥于ListView的线性展示方式,它也可以实现GridView、瀑布流等多种效果。
  • (3) 有可控的Item分隔线,通过继承RecylerView的ItemDecoration这个类定义添加,然后针对自己的业务需求去抒写代码。
  • (4) 可以控制Item增删的动画,通过ItemAnimator这个类进行控制,当然针对增删的动画,RecylerView有其自己默认的实现。

3.RecyclerView 的简单使用(以AS为例)

接下来就让我们看看,这个神奇的控件的使用:
3.1 初步使用
  • 添加依赖
dependencies {
...
compile 'com.android.support:recyclerview-v7:21.0.+'
}
  • 使用步骤
首先我们先看下布局的实现:

<RelativeLayout xmlns:android="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">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"/>
</RelativeLayout>
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);  
LinearLayoutManager layoutManager = new LinearLayoutManager(this );  
//设置布局管理器  
recyclerView.setLayoutManager(layoutManager);  
//设置为垂直布局,这也是默认的  
layoutManager.setOrientation(OrientationHelper. VERTICAL);  
//设置Adapter  
recyclerView.setAdapter( recycleAdapter);  
 //设置分隔线  
recyclerView.addItemDecoration( new DividerGridItemDecoration(this ));  
//设置增加或删除条目的动画  
recyclerView.setItemAnimator( new DefaultItemAnimator());  

可以从上面的使用步骤看出,相较于ListView的使用更加复杂了,这也就是RecyclerView具有高度的解偶性的表现,所谓舍得,即便代码书写增加了复杂性,但换回了可扩展性的增加。
接下来我们来继续了解RecyclerView的Adapter的使用,其实这和ListView的Adapter还是有区别的,RecyclerView的Adapter只实现三个固定方法:

  • (1) onCreateViewHolder()
    这个方法主要生成为每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。该方法把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例。当然,这个ViewHolder需要我们自己去编写。这样的好处就是直接省去了原先编写Listview的Adapter时的convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。
  • (2) onBindViewHolder()
    这个方法主要用于绑定数据到View中。方法给我们提供了一个viewHolder(自定义继承了RecyclerView 的 ViewHolder 的类型),而不是原来的convertView。
  • (3) getItemCount()
    这个方法就类似于BaseAdapter的getCount方法了,可获取总共有多少个条目。

接下来我们写个小的案例,直观展示:

每个条目的布局展示
<?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="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="@dimen/space_50dp"
        android:gravity="center"
        android:text="测试"
        />

</LinearLayout>
整体代码(其中使用了注解库ButterKnife)

import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.adjuz.myyupaopao.R;
import com.adjuz.myyupaopao.base.BaseActivity;
import com.cjj.MaterialRefreshLayout;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by shanfuming on 2017/4/20.
 */

public class RecyclerviewAc extends BaseActivity {

    private ArrayList<String> mData = new ArrayList<>();

    @BindView(R.id.recycleView)
    RecyclerView mRecyclerView;
    @BindView(R.id.mrl_refreshLayout)
    MaterialRefreshLayout materialRefreshLayout;
    private MyAdapter myAdapter;

    @Override
    protected void initView() {
        setContentView(R.layout.activity_recyclerviewac);
        ButterKnife.bind(this);

    }

    @Override
    protected void initData() {

        for (int i = 0; i < 40; i++) {
            mData.add("展示-" + i);
        }

        myAdapter = new MyAdapter(mData);
        //设置布局管理器
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //这个是默认设置的(横纵向滑动展示)
        linearLayoutManager.setOrientation(OrientationHelper.VERTICAL);
        //linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        //设置为Grid布局,需添加此布局管理器
        //linearLayoutManager = new GridLayoutManager(context,columNum);
mRecyclerView.setLayoutManager(linearLayoutManager);
        //设置Adapter
        mRecyclerView.setAdapter(myAdapter);

    }

    class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{

        private ArrayList<String> mList;
        private LayoutInflater inflater;

        public MyAdapter(ArrayList<String> list) {
            this.mList = list;
            inflater = LayoutInflater.from(RecyclerviewAc.this);
        }

        /**
         * 返回我们自定义继承了ViewHolder 的MyViewHolder
         * @param parent
         * @param viewType
         * @return
         */
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = inflater.inflate(R.layout.item_recyclerview,parent,false);
            MyViewHolder myViewHolder = new MyViewHolder(view);
            return myViewHolder;
        }

        /**
         * 将view 与数据进行绑定
         * @param holder
         * @param position
         */
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            holder.textView.setText(mList.get(position));
        }

        /**
         * 返回数据的总个数
         * @return
         */
        @Override
        public int getItemCount() {
            return mList.size();
        }

        class MyViewHolder extends RecyclerView.ViewHolder{

            @BindView(R.id.tv_name)
            TextView textView;

            public MyViewHolder(View itemView) {
                super(itemView);
                ButterKnife.bind(this,itemView);
            }
        }
    }
}

效果如下:看起来和ListView实现的效果没区别。
效果图

完成这个小案例,大家有没有觉得这个控件的好处呢,Adapter的书写,onCreateViewHolder()中初始化View,然后返回一个ViewHolder,其实就相当于ListView的Adapter中的getView()中的contentView.getTag(),包括之后的数据绑定,整体都变得更加的简洁且清晰。现在确实很不符合审美,最起码应该加上分割线,接下来就到这个模块了。

3.2 RecyclerView 添加分割线

当我们去寻找类似Listview的divider属性时,会发现RecyclerView根本不支持这个属性,那我们怎么办呢?之前我们说过,可以通过RecyclerView.addItemDecoration(ItemDecoration decoration)这个方法进行设置,其中它需要的参数就是自己定义的继承自ItemDecoration的一个对象。当然像我们上面的例子ItemDecoration我们并没有设置也可以正常运行,那说明ItemDecoration并不是强制需要使用,作为开发者可以设置或者不设置Decoration。系统为我们提供了ItemDecoration,该类为抽象类,官方目前并没有提供默认的实现类,具体源码如下:

public static abstract class ItemDecoration {   
        public void onDraw(Canvas c,RecyclerView parent,State state) {   
          onDraw(c,parent);   
      }   
      public void onDrawOver(Canvas c,RecyclerView parent,State state) {   
          onDrawOver(c,parent);   
      }   
      public void getItemOffsets(RectoutRect, View view,RecyclerView parent,State state) {   
          getItemOffsets(outRect,((LayoutParams)view.getLayoutParams()).getViewLayoutPosition(),parent);   
      }   
  } 

当我们调用mRecyclerView.addItemDecoration()方法添加decoration的时候,RecyclerView在绘制的时候,调用该类的onDraw和onDrawOver方法

  • onDraw方法先于drawChildren

  • onDrawOver在drawChildren之后,一般我们选择复写其中一个即可。

  • getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator。

接下来我们看一下RecyclerView.ItemDecoration的实现类,该类很好的实现了RecyclerView添加分割线(当使用LayoutManager为LinearLayoutManager时)。

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.util.Log;
import android.view.View;
/**
 * 这个类是v-7包中自带的,并不是我自定义的
 */
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);
        }
    }
}

该类可设置横纵向分割线,我们在源代码的基础上加一句代码即可(此默认颜色为灰色,先不展示效果了):

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

该分割线是系统默认提供的,你可以在theme.xml中找到该属性的使用情况。这样方便我们去随意的改变,该属性我们可以直接声明在:

<!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
      <item name="android:listDivider">@drawable/divider_bg</item>  
    </style>

然后自己写个drawable即可,下面我们自编辑分隔符样式:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <gradient
        android:centerColor="#ff00ff00"
        android:endColor="#ff0000ff"
        android:startColor="#ffff0000"
        android:type="linear" />
    <size android:height="4dp" android:width="@dimen/space_4dp"/>

</shape>

带有自定义分隔符的效果图

当然这个样式是可以随意玩的。

不过写到这里,确实看起来和Listview 展示没区别,而且代码更烦了,但是不要着急,接下来我们尝试GridView的实现,你会发现,修改起来十分方便:

上边我们使用的代码是这样的:

//设置布局管理器
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //这个是默认设置的
        linearLayoutManager.setOrientation(OrientationHelper.VERTICAL);
        mRecyclerView.setLayoutManager(linearLayoutManager);

我们之前简单介绍过它的布局管理器:当实现GridView时,我们直接替换使用GridLayoutManager(表格布局)即可,修改分分钟解决:

mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));
//StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL);

这样对于前面的分割线就不再适用了,因为DividerItemDecoration 的计算绘制,是针对一行多个item进行的,但是GridView 是多行了,所以就要进行多次绘制,并且GridLayoutManager时,Item如果为最后一列(则右边无间隔线)或者为最后一行(底部无分割线)。

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

接下来我们直接引用 鸿洋大神 定义的分割线了:

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.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;

/**
 * 
 * @author zhy
 * 
 */
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);

    }

    private int getSpanCount(RecyclerView parent)
    {
        // 列数
        int spanCount = -1;
        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)
    {
        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)
    {
        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());
        }
    }
}

不要忘记修改代码:

DividerGridItemDecoration dividerGridItemDecoration = new DividerGridItemDecoration(this);
        mRecyclerView.addItemDecoration(dividerGridItemDecoration);

这里写图片描述

怎么样,到这里,是不是觉得RecyclerView真的很强大了,样式的切换只需要几行代码的改变,如此简便!还有横向的滑动效果(这里就不展示效果了,可以写下试试):

StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.HORIZONTAL);  
//设置布局管理器  
mRecyclerView.setLayoutManager(layoutManager);  

值得注意的是,当StaggeredGridLayoutManager布局管理器的第二个参数是StaggeredGridLayoutManager.VERTICAL时,第一个传入的int参数代表是行数;当StaggeredGridLayoutManager布局管理器的第二个参数是StaggeredGridLayoutManager.HORIZONTAL时,第一个传入的int参数代表是列数,这个效果和上边的是一样的;

可以看到,固定行数或列数,随意改变横向纵向,要注意的是,横向滑动时,要改变下item 布局的宽度,具体什么原因,大家写写就知道了。

4.RecyclerView 条目的增加与删除(包括动画)的介绍

4.1 增加或删除的功能

在Activity 中添加一下代码:

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId())
        {
            case R.id.action_add:
                myAdapter.addData(1);
                break;
            case R.id.action_remove:
                myAdapter.removeData(1);
                break;
        }
        return true;
    }

<?xml version="1.0" encoding="utf-8"?>

R.menu.main(在res 文件下创建menu文件夹下添加main.xml)代码 :

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context="example.gmariotti.it.test21.TaylorActivity">

    <item android:id="@+id/action_add"
        android:title="ADD"
        android:orderInCategory="100"
        app:showAsAction="always" />

    <item android:id="@+id/action_remove"
        android:title="REMOVE"
        android:orderInCategory="100"
        app:showAsAction="always" />
</menu>

在Adapter 中添加以下两个函数:

        /**
         * 动态增加或删除条目
         * @param position
         */
        public void addData(int position) {
            mList.add(position, "add One");
            notifyItemInserted(position);
            notifyDataSetChanged();
        }

        public void removeData(int position) {
            mList.remove(position);
            notifyItemRemoved(position);
            notifyDataSetChanged();
        }

这里我们更新数据使用的不是notifyDataSetChanged() 而是notifyItemInsert()和notifyItemRemove() 否则没有动画效果(但这里还是加了notifyDataSetChanged,是因为动态添加多个item时,点击事件位置不对,调用了就不会有问题);
这是从其他优秀开发者借鉴的图片:

4.2 修改增删动画效果

系统为我们提供了默认实现类,借助默认的实现,当Item添加和移除的时候,添加动画效果很简单:

//设置增加或删除条目的动画  
mRecyclerView.setItemAnimator( new DefaultItemAnimator());  

编辑RecyclerView 的点击事件

相信大家在使用ListView时已经习惯了设置点击事件,它给我们提供了封装好的OnItemClickListener,然而对于RecyclerView,很可惜并没有给我们提供任何的点击监听,但我们可以模仿自己添加监听方法,接下来我们在Adapter 中添加两个函数:

class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{

//...
    public interface OnItemClickLitener
    {
        void onItemClick(int position);
        void onItemLongClick(int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
    {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position)
    {
        holder.textview.setText(mList.get(position));

        // 如果设置了回调,则设置点击事件
        if (mOnItemClickLitener != null)
        {
            holder.itemView.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    mOnItemClickLitener.onItemClick(position);
                }
            });

            holder.itemView.setOnLongClickListener(new OnLongClickListener()
            {
                @Override
                public boolean onLongClick(View v)
                {
                    mOnItemClickLitener.onItemLongClick(position);
                    return false;
                }
            });
        }
    }
//...
}

正如以上所写,添加了自定义点击事件的监听接口,然后在onBindViewHolder 进行相应设置。

在activity 中代码实现:

myAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
            @Override
            public void onClick1(int position) {
                Toast.makeText(RecyclerviewAc.this,"点击了第"+position+"位置",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLongClick(int position) {
                Toast.makeText(RecyclerviewAc.this,"长按了第"+position+"位置",Toast.LENGTH_SHORT).show();
            }
        });

这里就不上效果图了,点击效果很简单,一个提示而已。到这里RecyclerView的点击事件也基本结束。

结合MaterialRefreshLayout 构成流畅而优雅的刷新和加载更多

给大家推荐一个不错的刷新和加载控件,操作简单,配合RecyclerView一起使用,可满足大多数需求了。

这次总结就到这里,如果有什么建议或意见,欢迎留言!再次感谢两篇博文的参考。

源码地址

以上博文参考地址:(http://blog.csdn.net/skykingf/article/details/50827141)

[http://blog.csdn.net/lmj623565791/article/details/45059587]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值