RecycleView使用详解

来源:互联网 发布:sql语句查询多张表 编辑:程序博客网 时间:2024/05/29 12:50

RecyclerView不属于MD系列,但是却常常一起使用。

一、Reclycler的作用和优点

用来干嘛—— 代替 ListView个GridView。

  • 自带ViewHolder
  • 分割线控制方便
  • 横向,竖向、列表,多行列表和流式皆可
  • item增删动画控制方便

二、简单使用

以前没有RecyclerView,我们要使用RecyclerView可以引入下面这个

com.android.support:recyclerview-v7:23.4.0

不过你要是使用md设计,也以这样如下引用就好 (本文采用的就是这样)

    compile 'com.android.support:appcompat-v7:23.4.0'    compile 'com.android.support:design:23.4.0'

support:design 里面应该包含了 support:recyclerview 。

最基本的使用:

布局文件

<?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:orientation="vertical">    <android.support.v7.widget.RecyclerView        android:id="@+id/mRecycler"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:divider="#ffff0000"        android:dividerHeight="10dp"        >    </android.support.v7.widget.RecyclerView></RelativeLayout>

.
.
item布局

<?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"    android:background="#66ff0000"    android:padding="5dp"    >    <TextView        android:id="@+id/mTvTitle"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="标题"        android:textSize="20sp"        android:padding="10dp"        android:textColor="#ff0000"        android:background="#4f92c9"        />    <TextView        android:id="@+id/mTvDesc"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="描述"        android:textSize="16sp"        android:padding="10dp"        android:textColor="#3657d7"        android:background="#a9a667"        /></LinearLayout>

.
.
MainActivity

public class MainActivity extends AppCompatActivity {    private RecyclerView mRecyclerView;    private List<DataBean> mDatas;    private TestAdapter mAdapter;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initData();        mRecyclerView = (RecyclerView) findViewById(R.id.mRecycler);        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));        mRecyclerView.setAdapter(mAdapter = new TestAdapter());    }    protected void initData()    {        mDatas = new ArrayList<DataBean>();        DataBean dataBean = null;        for (int i = 0; i < 20; i++)        {            dataBean = new DataBean();            dataBean.title = "标题  "+i;            dataBean.desc = "描述一下  "+i;            mDatas.add(dataBean);        }    }    class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyViewHolder>{        // 孩子数        @Override        public int getItemCount() {            return mDatas.size();        }        // 创建视图        @Override        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            MyViewHolder myViewHolder = new MyViewHolder(LayoutInflater.from(MainActivity.this)                    .inflate(R.layout.item_recy_test,parent, false));            return myViewHolder;        }        // 绑定视图视图  以前getView的事情  关键方法        @Override        public void onBindViewHolder(MyViewHolder holder, int position) {            DataBean dataBean = mDatas.get(position);            holder.mTvTitle.setText(dataBean.title);            holder.mTvDesc.setText(dataBean.desc);        }        // 必须实现的Holder        class MyViewHolder extends RecyclerView.ViewHolder        {            TextView mTvTitle;            TextView mTvDesc;            public MyViewHolder(View itemView) {                super(itemView);                mTvTitle = (TextView) itemView.findViewById(R.id.mTvTitle);                mTvDesc = (TextView) itemView.findViewById(R.id.mTvDesc);            }        }    }}

.
.
效果图


最简单的例子.gif

少年我知道你不是伸手党,你会自己去打一遍,而且不怎么看代码。如果你遇到了下面的问题,那你可以看看

  • 问题1、为什么RecyclerView的数据没显示出来?

遥想当年,我们设置ListView,find到ListView之后满脑海想的就是setAdapter,然后在这里我们也是这么做,所以,没显示出来


Paste_Image.png


很有可能是你没设置 LayoutManager,LayoutManager对于RecyclerView是一个很重要的概念。

结果就像现在下图


Paste_Image.png
  • 问题2、明明就是item就是match_parent,但是为什么只显示一部分?

还是需要遥想当年,左牵黄,右擎苍,潇潇洒洒地在ListView的getView方法的时候,我们总是传入layout布局,然后就null,写顺手了。


Paste_Image.png

如果写成上图备注的样子,即父亲为null,就会出现下图的状况


Paste_Image.png

三、列表分割线

我们说过,RecyclerView自带设置分割线,(但是却没有分割线的样式可以选,必须自己实现)
先听一下,回头看一下我们之前activity_main的布局文件


Paste_Image.png

我们设置分割线,但是安卓ListView的做法设置分割线没有显示。

现在我们来设置分割线
RecyclerView自带设置分割线的api

mRecyclerView.addItemDecoration((ItemDecoration decor);

我们分割线的样式需要自己实现
下面附上一份分割线样式代码 参考

public class RecycleViewDivider extends RecyclerView.ItemDecoration {    private Paint mPaint;    private Drawable mDivider;    private int mDividerHeight = 2;//分割线高度,默认为1px    private int mOrientation;//列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};    /**     * 默认分割线:高度为2px,颜色为灰色     *     * @param context     * @param orientation 列表方向     */    public RecycleViewDivider(Context context, int orientation) {        if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {            throw new IllegalArgumentException("请输入正确的参数!");        }        mOrientation = orientation;        final TypedArray a = context.obtainStyledAttributes(ATTRS);        mDivider = a.getDrawable(0);        a.recycle();    }    /**     * 自定义分割线     *     * @param context     * @param orientation 列表方向     * @param drawableId  分割线图片     */    public RecycleViewDivider(Context context, int orientation, int drawableId) {        this(context, orientation);        mDivider = ContextCompat.getDrawable(context, drawableId);        mDividerHeight = mDivider.getIntrinsicHeight();    }    /**     * 自定义分割线     *     * @param context     * @param orientation   列表方向     * @param dividerHeight 分割线高度     * @param dividerColor  分割线颜色     */    public RecycleViewDivider(Context context, int orientation, int dividerHeight, int dividerColor) {        this(context, orientation);        mDividerHeight = dividerHeight;        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mPaint.setColor(dividerColor);        mPaint.setStyle(Paint.Style.FILL);    }    //获取分割线尺寸    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        outRect.set(0, 0, 0, mDividerHeight);    }    //绘制分割线    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        super.onDraw(c, parent, state);        if (mOrientation == LinearLayoutManager.VERTICAL) {            drawVertical(c, parent);        } else {            drawHorizontal(c, parent);        }    }    //绘制横向 item 分割线    private void drawHorizontal(Canvas canvas, RecyclerView parent) {        final int left = parent.getPaddingLeft();        final int right = parent.getMeasuredWidth() - parent.getPaddingRight();        final int childSize = parent.getChildCount();        for (int i = 0; i < childSize; i++) {            final View child = parent.getChildAt(i);            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();            final int top = child.getBottom() + layoutParams.bottomMargin;            final int bottom = top + mDividerHeight;            if (mDivider != null) {                mDivider.setBounds(left, top, right, bottom);                mDivider.draw(canvas);            }            if (mPaint != null) {                canvas.drawRect(left, top, right, bottom, mPaint);            }        }    }    //绘制纵向 item 分割线    private void drawVertical(Canvas canvas, RecyclerView parent) {        final int top = parent.getPaddingTop();        final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();        final int childSize = parent.getChildCount();        for (int i = 0; i < childSize; i++) {            final View child = parent.getChildAt(i);            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();            final int left = child.getRight() + layoutParams.rightMargin;            final int right = left + mDividerHeight;            if (mDivider != null) {                mDivider.setBounds(left, top, right, bottom);                mDivider.draw(canvas);            }            if (mPaint != null) {                canvas.drawRect(left, top, right, bottom, mPaint);            }        }    }}

.
.
设置分割线:

        mRecyclerView = (RecyclerView) findViewById(R.id.mRecycler);        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));        mRecyclerView.addItemDecoration(new RecycleViewDivider(MainActivity.this, LinearLayoutManager.VERTICAL)); // 设置分割线        mRecyclerView.setAdapter(mAdapter = new TestAdapter());

发现只需要在原来的代码上加上一行代码

        mRecyclerView.addItemDecoration(new RecycleViewDivider(MainActivity.this,

效果图:


Paste_Image.png

看得很辛苦,那么我们让分割线加大一些,指定一下颜色吧

        mRecyclerView.addItemDecoration(new RecycleViewDivider(MainActivity.this,                                 LinearLayoutManager.VERTICAL,20, Color.GRAY)); // 设置分割线

Paste_Image.png

四、布局管理器

RecyclerView.LayoutManager,这是一个抽象类,系统提供了3个实现类:

LinearLayoutManager 线性管理器,支持横向、纵向。
GridLayoutManager 网格布局管理器
StaggeredGridLayoutManager 瀑布就式布局管理器

说说LinearLayoutManager

LinearLayoutManager 我们上面用的一直是纵向。

现在来设置成为横向的:


Paste_Image.png
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); // 创建线性布局管理器        linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // 设置线性布局为横向(默认为纵向)        mRecyclerView.setLayoutManager(linearLayoutManager); // 设置布局管理器

横向.gif

说说GridLayoutManager

  • 纵向
mRecyclerView = (RecyclerView) findViewById(R.id.mRecycler);        mRecyclerView.setLayoutManager(new C(this,2)); // 设置布局管理器 GridView        mRecyclerView.addItemDecoration(new RecycleViewDivider(MainActivity.this, GridLayoutManager.VERTICAL)); // 设置分割线        mRecyclerView.setAdapter(mAdapter = new TestAdapter());

效果


GV.gif
  • 横向

利用 StaggeredGridLayoutManager

只需要一行代码:

mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.HORIZONTAL)); // 设置布局管理器 GridView

不过布局有一点点需要改动
activity_main的RecyclerView高度需要包裹,不能填充父窗体

<?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:orientation="vertical">    <android.support.v7.widget.RecyclerView        android:id="@+id/mRecycler"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:divider="#ffff0000"        android:dividerHeight="10dp"></android.support.v7.widget.RecyclerView></RelativeLayout>

item布局宽度不能填充父窗体

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="180dp"    android:layout_height="100dp"    android:orientation="vertical"    android:background="#66ff0000"    android:padding="5dp"    >    <TextView        android:id="@+id/mTvTitle"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="标题"        android:textSize="20sp"        android:padding="10dp"        android:textColor="#ff0000"        android:background="#4f92c9"        />    <TextView        android:id="@+id/mTvDesc"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="描述"        android:textSize="16sp"        android:padding="10dp"        android:textColor="#3657d7"        android:background="#a9a667"        /></LinearLayout>

效果:


横向多行.gif

说说StaggeredGridLayoutManager 流式布局

在上面的横向布局里面,我们已经用到了StaggeredGridLayoutManager

做的东西就几点:
1、item布局需要在外层给出具体高度,这样方便待会计算的时候保证最低高度
2、在RecyclerView.Adapter的继承类的onBindViewHolder里面动态改变高度

接下来看代码:
item布局里面,我们给最外层指定了最低高度100dp,最低宽度180dp

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/mLlItemRoot"    android:layout_width="180dp"    android:layout_height="100dp"    android:orientation="vertical"    android:background="#66ff0000"    android:padding="5dp"    android:gravity="center"    android:layout_margin="2dp"    >    <TextView        android:id="@+id/mTvTitle"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="标题"        android:layout_gravity="center_horizontal"        android:textSize="20sp"        android:padding="10dp"        android:textColor="#ff0000"        android:background="#4f92c9"        />    <TextView        android:id="@+id/mTvDesc"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="描述"        android:textSize="16sp"        android:gravity="center_horizontal"        android:padding="10dp"        android:textColor="#3657d7"        android:background="#a9a667"        /></LinearLayout>

.
.

接下来是adapter,主要看 onBindViewHolder方法

public  class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyViewHolder>{    private List<DataBean> mDatas;    private Context mContext;    private LayoutInflater mInflater;    private List<Integer> mHeights;    public TestAdapter(Context mContext, List<DataBean> mDatas) {        mInflater = LayoutInflater.from(mContext);        this.mContext = mContext;        this.mDatas = mDatas;        mHeights = new ArrayList<Integer>();        for (int i = 0; i < mDatas.size(); i++)        {            // 这里为什么是300? 因为item的高度我们给的是100.如果item不给实际高度,那么lp.height拿出来的很可能是个负数            // 我给item的值100,但是下面lp.height给出来的是300,才写了300            mHeights.add( 300+(int) (Math.random() * 100));        }    }    // 孩子数    @Override    public int getItemCount() {        return mDatas.size();    }    // 创建视图    @Override    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        // 应该调用三个参数的inflate方法,传入父亲(parent)        MyViewHolder myViewHolder = new MyViewHolder(mInflater.inflate(R.layout.item_recy_test,parent, false));        return myViewHolder;    }    // 绑定视图视图  以前getView的事情  关键方法    @Override    public void onBindViewHolder(MyViewHolder holder, int position) {        ViewGroup.LayoutParams lp = holder.mLlItemRoot.getLayoutParams();        //        if(position==1){            System.out.println("===========lp.height:  "+lp.height);            System.out.println("===========lp.height + 50 :  "+(lp.height+50));        }        lp.height = mHeights.get(position);        holder.mLlItemRoot.setLayoutParams(lp);        DataBean dataBean = mDatas.get(position);        holder.mTvTitle.setText(dataBean.title);        holder.mTvDesc.setText(dataBean.desc);    }    // 必须实现的Holder    class MyViewHolder extends RecyclerView.ViewHolder    {        TextView mTvTitle;        TextView mTvDesc;        LinearLayout mLlItemRoot;        public MyViewHolder(View itemView) {            super(itemView);            mLlItemRoot = (LinearLayout) itemView.findViewById(R.id.mLlItemRoot);            mTvTitle = (TextView) itemView.findViewById(R.id.mTvTitle);            mTvDesc = (TextView) itemView.findViewById(R.id.mTvDesc);        }    }}

还要需要注意的就是这句代码

mHeights.add( 300+(int) (Math.random() * 100));

这里为什么是300? 因为item的高度我们给的是100.如果item不给实际高度,那么lp.height拿出来的很可能是个负数
我给item的值100,但是下面lp.height给出来的是300,才写了300

为什么要把高度写在集合里面而不写在onBindViewHolder?
如果这样循环往复拉动几次会出现什么状况?高度越来越大,每次都上在上次的基础上扩大。

.
.
MainActivity

public class MainActivity extends AppCompatActivity {    private RecyclerView mRecyclerView;    private List<DataBean> mDatas;    private TestAdapter mAdapter;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initData();        mRecyclerView = (RecyclerView) findViewById(R.id.mRecycler);        mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL)); // 设置布局管理器 GridView        mRecyclerView.addItemDecoration(new DividerGridItemDecoration(MainActivity.this)); // 设置分割线        mRecyclerView.setAdapter(mAdapter = new TestAdapter(MainActivity.this,mDatas));    }    protected void initData()    {        mDatas = new ArrayList<DataBean>();        DataBean dataBean = null;        for (int i = 0; i < 20; i++)        {            dataBean = new DataBean();            dataBean.title = "标题  "+i;            dataBean.desc = "描述一下  "+i;            mDatas.add(dataBean);        }    }}

.
.
在上面的代码这句

mRecyclerView.addItemDecoration(new DividerGridItemDecoration(MainActivity.this)); // 设置分割线

我们还用到了一个分割线文件
附上分割线文件,参考csdn 鸿洋

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

效果:


流式.gif

感觉有点丑,后面我们可以用CradView感觉就会好很多。

五、item的增删动画 ItemAnimator

我们之前ListView的时候,通知试图刷新变化调用的是 notifyDataSetChanged()

而在RecyclerView,除了notifyDataSetChanged(),还有

  • 添加 notifyItemInserted(position) 指定位置添加一个item
  • 删除 notifyItemRemoved(position) 指定删除哪一个item

既然知道怎么添加和删除,那么我们就在adapter里面新增两个对用的方法

    public void addData(int position)    {        DataBean tempAdd = new DataBean();        tempAdd.title="新增标题";        tempAdd.desc="新增描述";        mDatas.add(position, tempAdd);        mHeights.add( 300+(int) (Math.random() * 100));        notifyItemInserted(position);    }    public void removeData(int position)    {        mDatas.remove(position);        notifyItemRemoved(position);    }

然后我们弄两个按钮,点击就调用方法

        mTvAdd = (TextView) findViewById(R.id.mTvAdd);        mTvAdd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                mAdapter.addData(1);            }        });        mTvRemove = (TextView) findViewById(R.id.mTvRemove);        mTvRemove.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                mAdapter.removeData(1);            }        });

效果图


增删.gif

我们发现这个增删的过程还是有动画的,这是RecyclerView我们实现的默认动画。

 mRecyclerView = (RecyclerView) findViewById(R.id.mRecycler);        mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL)); // 设置布局管理器 GridView        mRecyclerView.addItemDecoration(new DividerGridItemDecoration(MainActivity.this)); // 设置分割线        // 设置item动画        mRecyclerView.setItemAnimator(new DefaultItemAnimator());        mRecyclerView.setAdapter(mAdapter = new TestAdapter(MainActivity.this,mDatas));

Paste_Image.png

我们也可以利用ItemAnimator()实现动画。

六、自己实现点击事件

RecyclerView没有点击回调的方法方法可以用,我们需要自己实现

    // 点击回调    public interface OnItemClickLitener    {        void onItemClick(View view, int position);  // 点击        void onItemLongClick(View view , int position); // 长按    }    private OnItemClickLitener mOnItemClickLitener;    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)    {        this.mOnItemClickLitener = mOnItemClickLitener;    }    // 绑定视图视图  以前getView的事情  关键方法    @Override    public void onBindViewHolder(final MyViewHolder holder, int position) {        ViewGroup.LayoutParams lp = holder.mLlItemRoot.getLayoutParams();        // 如果设置了回调,则设置点击事件        if (mOnItemClickLitener != null)        {            holder.itemView.setOnClickListener(new View.OnClickListener()            {                @Override                public void onClick(View v)                {                    int pos = holder.getLayoutPosition();                    mOnItemClickLitener.onItemClick(holder.itemView, pos);                }            });            holder.itemView.setOnLongClickListener(new View.OnLongClickListener()            {                @Override                public boolean onLongClick(View v)                {                    int pos = holder.getLayoutPosition();                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);                    return false;                }            });        }}

效果图


点击.gif

到这里,回顾开头我们说的

  • 自带ViewHolder
  • 分割线控制方便
  • 横向,竖向、列表,多行列表和流式皆可
  • item增删动画控制方便

都言及了。

七、CardView 的配合使用

对于CardView,你可以简单的认为它是一个使用了Material Desgin风格的FrameLayout,只不过比普通的FrameLayout多了圆角背景和阴影效果。所以它常用作ListView 或者 RecyclerView等视图Item的布局容器;

我们自然可以联想到它的使用跟FrameLayout非常相似,只不多多了几个用于控制圆角、阴影等自身特有的属性:

design里面没有包含CardView
所以我们还需要引入CardView

    compile 'com.android.support:appcompat-v7:23.4.0'    compile 'com.android.support:design:23.4.0'    compile 'com.android.support:cardview-v7:23.4.0'   // 引入 cardview

接下来,把itme的布局文件最外层设置为CardView

<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/mCvItemRoot"    android:layout_width="180dp"    android:layout_height="100dp"    xmlns:card_view="http://schemas.android.com/apk/res-auto"    card_view:cardBackgroundColor="@color/cardview_dark_background"    card_view:cardCornerRadius="10dp"    card_view:cardElevation="8dp"    android:layout_margin="3dp"    >    <LinearLayout        android:id="@+id/mLlItemRoot"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical"        android:padding="5dp"        android:gravity="center"        android:layout_margin="2dp">    <TextView        android:id="@+id/mTvTitle"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="标题"        android:layout_gravity="center_horizontal"        android:textSize="20sp"        android:padding="10dp"        android:textColor="#ff0000"        android:background="#4f92c9"        />    <TextView        android:id="@+id/mTvDesc"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1"        android:text="描述"        android:textSize="16sp"        android:gravity="center_horizontal"        android:padding="10dp"        android:textColor="#3657d7"        android:background="#a9a667"        />    </LinearLayout></android.support.v7.widget.CardView>

其中关键代码无非这两句

    card_view:cardBackgroundColor="@color/cardview_dark_background"    card_view:cardCornerRadius="10dp"    card_view:cardElevation="8dp"

第一句指定颜色
第二句指定圆角角度
第三句指定阴影


Paste_Image.png

当然Adapter也有相应的变化
起始就是把原来的 LinearLayout 换成 CardView ,计算高度也是换成 CardView 而已,为了让流式效果明显一些,我们把随机生成的高度弄大了一些。

 public  class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyViewHolder>{    private List<DataBean> mDatas;    private Context mContext;    private LayoutInflater mInflater;    private List<Integer> mHeights;    public TestAdapter(Context mContext, List<DataBean> mDatas) {        mInflater = LayoutInflater.from(mContext);        this.mContext = mContext;        this.mDatas = mDatas;        mHeights = new ArrayList<Integer>();        for (int i = 0; i < mDatas.size(); i++)        {            // 这里为什么是300? 因为item的高度我们给的是100.如果item不给实际高度,那么lp.height拿出来的很可能是个负数            // 我给item的值100,但是下面lp.height给出来的是300,才写了300            mHeights.add( 300+(int) (Math.random() * 200));        }    }    // 孩子数    @Override    public int getItemCount() {        return mDatas.size();    }    // 创建视图    @Override    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        // 应该调用三个参数的inflate方法,传入父亲(parent)        MyViewHolder myViewHolder = new MyViewHolder(mInflater.inflate(R.layout.item_recy_test,parent, false));        return myViewHolder;    }    // 点击回调    public interface OnItemClickLitener    {        void onItemClick(View view, int position);  // 点击        void onItemLongClick(View view , int position); // 长按    }    private OnItemClickLitener mOnItemClickLitener;    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)    {        this.mOnItemClickLitener = mOnItemClickLitener;    }    // 绑定视图视图  以前getView的事情  关键方法    @Override    public void onBindViewHolder(final MyViewHolder holder, int position) {        // 如果设置了回调,则设置点击事件        if (mOnItemClickLitener != null)        {            holder.itemView.setOnClickListener(new View.OnClickListener()            {                @Override                public void onClick(View v)                {                    int pos = holder.getLayoutPosition();                    mOnItemClickLitener.onItemClick(holder.itemView, pos);                }            });            holder.itemView.setOnLongClickListener(new View.OnLongClickListener()            {                @Override                public boolean onLongClick(View v)                {                    int pos = holder.getLayoutPosition();                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);                    return false;                }            });        }        ViewGroup.LayoutParams lp = holder.mCvItemRoot.getLayoutParams();        if(position==1){            System.out.println("===========lp.height:  "+lp.height);            System.out.println("===========lp.height + 50 :  "+(lp.height+50));        }        lp.height = mHeights.get(position);        holder.mCvItemRoot.setLayoutParams(lp);        DataBean dataBean = mDatas.get(position);        holder.mTvTitle.setText(dataBean.title);        holder.mTvDesc.setText(dataBean.desc);    }    // 必须实现的Holder    class MyViewHolder extends RecyclerView.ViewHolder    {        TextView mTvTitle;        TextView mTvDesc;        LinearLayout mLlItemRoot;        CardView mCvItemRoot;        public MyViewHolder(View itemView) {            super(itemView);            mCvItemRoot = (CardView) itemView.findViewById(R.id.mCvItemRoot);            mLlItemRoot = (LinearLayout) itemView.findViewById(R.id.mLlItemRoot);            mTvTitle = (TextView) itemView.findViewById(R.id.mTvTitle);            mTvDesc = (TextView) itemView.findViewById(R.id.mTvDesc);        }    }    public void addData(int position)    {        DataBean tempAdd = new DataBean();        tempAdd.title="新增标题";        tempAdd.desc="新增描述";        mDatas.add(position, tempAdd);        mHeights.add( 300+(int) (Math.random() * 100));        notifyItemInserted(position);    }    public void removeData(int position)    {        mDatas.remove(position);        notifyItemRemoved(position);    }}

CardView简单演示.gif

八、下拉刷新和上拉加载更多

ANDROID官方的SwipeRefreshLayout可用于刷新,但是这个只是做下拉刷新。
而下拉刷新需要判断列表是否抵达底部、

所以需要注意两点:
一是用 SwipeRefreshLayout 包裹 RecyclerView 实现下拉刷新。
下拉刷新是通过实现 SwipeRefreshLayout.OnRefreshListener 接口来实现的,也就是说下拉刷新具有了通用性,不只是 RecyclerView ;

二是滑倒底部的时候自动加载实现加载更多。
加载更多要通过 LayoutManager 来获取 RecyclerView 是否滑动到底部来实现。

下拉刷新

说起来就是几步
1、RecyclerView 外层需要包一个 SwipeRefreshLayout
2、給SwipeRefreshLayout设置颜色

mSwipeRefresh.setColorSchemeResources(                R.color.google_blue,                R.color.google_green,                R.color.google_red,                R.color.google_yellow        );

3、回调接口

  mSwipeRefresh.setOnRefreshListener(this); //复写onRefresh方法 做下拉刷新  ...   @Override    public void onRefresh() {        new Handler().postDelayed(new Runnable() {            @Override            public void run() {                DataBean addTemp = new DataBean();                addTemp.title = "标题 下拉新增";                addTemp.desc = "desc 下拉新增";                mDatas.add(0,addTemp);                mAdapter.notifyDataSetChanged();                mSwipeRefresh.setRefreshing(false); //            }        }, 1000);    }

大概步骤如上。
接下来看代码:

简单的下拉刷新的实现

<?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="match_parent"    android:orientation="vertical"    >    <LinearLayout          ...    </LinearLayout>    <android.support.v4.widget.SwipeRefreshLayout        android:id="@+id/mSwipeRefresh"        android:layout_width="match_parent"        android:layout_height="wrap_content">        <android.support.v7.widget.RecyclerView            android:id="@+id/mRecycler"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:divider="#ffff0000"            android:dividerHeight="10dp">        </android.support.v7.widget.RecyclerView>    </android.support.v4.widget.SwipeRefreshLayout></LinearLayout>

Mainactivity

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {    private RecyclerView mRecyclerView;    private TextView mTvAdd;    private TextView mTvRemove;    private List<DataBean> mDatas;    private TestAdapter mAdapter;    private SwipeRefreshLayout mSwipeRefresh;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mTvAdd = (TextView) findViewById(R.id.mTvAdd);        mTvAdd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                mAdapter.addData(1);            }        });        mTvRemove = (TextView) findViewById(R.id.mTvRemove);        mTvRemove.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                mAdapter.removeData(1);            }        });        mRecyclerView = (RecyclerView) findViewById(R.id.mRecycler);        initData();        mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL)); // 设置布局管理器 GridView        mRecyclerView.addItemDecoration(new DividerGridItemDecoration(MainActivity.this)); // 设置分割线        mRecyclerView.setItemAnimator(new DefaultItemAnimator());        // 设置item动画        mRecyclerView.setAdapter(mAdapter = new TestAdapter(MainActivity.this,mDatas));        mAdapter.setOnItemClickLitener(new TestAdapter.OnItemClickLitener() {            @Override            public void onItemClick(View view, int position) {                Toast.makeText(MainActivity.this,"点击:"+position,Toast.LENGTH_SHORT).show();            }            @Override            public void onItemLongClick(View view, int position) {                Toast.makeText(MainActivity.this,"长按:"+position,Toast.LENGTH_SHORT).show();            }        });        // 刷新        mSwipeRefresh = (SwipeRefreshLayout) findViewById(R.id.mSwipeRefresh);        // 刷新的时候的颜色        mSwipeRefresh.setColorSchemeResources(                R.color.google_blue,                R.color.google_green,                R.color.google_red,                R.color.google_yellow        );        // implements SwipeRefreshLayout.OnRefreshListener        mSwipeRefresh.setOnRefreshListener(this); //复写onRefresh方法 做下拉刷新        // 刷新    }    @Override    public void onRefresh() {        new Handler().postDelayed(new Runnable() {            @Override            public void run() {                DataBean addTemp = new DataBean();                addTemp.title = "标题 下拉新增";                addTemp.desc = "desc 下拉新增";                mDatas.add(0,addTemp);                mAdapter.notifyDataSetChanged();                mSwipeRefresh.setRefreshing(false); //            }        }, 1000);    }    protected void initData()    {        mDatas = new ArrayList<DataBean>();        DataBean dataBean = null;        for (int i = 0; i < 20; i++)        {            dataBean = new DataBean();            dataBean.title = "标题  "+i;            dataBean.desc = "描述一下  "+i;            mDatas.add(dataBean);        }    }}

.
.
效果图


下拉刷新.gif

上拉加载更多数据

上拉加载更多用一个新的页面展示,更加清晰。


上拉下拉.gif

主要就是完成从下面这几步:

  • 1、Adapter 定义两个常量区分普通item视图和脚部
      private static final int TYPE_ITEM = 0;  private static final int TYPE_FOOTER = 1;
  • 2、Adapter getItemCount()方法为脚部做调整
    @Override    public int getItemCount() {        return mDatas.size() == 0 ? 0 : mDatas.size() + 1;    }
  • 3、C利用getItemViewType做视图判断
    @Override  public int getItemViewType(int position) {      if (position + 1 == getItemCount()) {          return TYPE_FOOTER;      } else {          return TYPE_ITEM;      }  }
  • 4、Adapter onCreateViewHolder 初始化视图

    @Override  public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {      if (viewType == TYPE_ITEM) {          View view = LayoutInflater.from(context).inflate(R.layout.item_base, parent,                  false);          return new ItemViewHolder(view);      } else if (viewType == TYPE_FOOTER) {          View view = LayoutInflater.from(context).inflate(R.layout.item_foot, parent,                  false);          return new FootViewHolder(view);      }      return null;  }
  • 5、Adapter onBindViewHolder 帮顶视图做区分

    @Override  public void onBindViewHolder(final ViewHolder holder, int position) {      if (holder instanceof ItemViewHolder) {          if (onItemClickListener != null) {              holder.itemView.setOnClickListener(new View.OnClickListener() {                  @Override                  public void onClick(View v) {                      int position = holder.getLayoutPosition();                      onItemClickListener.onItemClick(holder.itemView, position);                  }              });              holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {                  @Override                  public boolean onLongClick(View v) {                      int position = holder.getLayoutPosition();                      onItemClickListener.onItemLongClick(holder.itemView, position);                      return false;                  }              });          }          ItemViewHolder itemViewHolder = (ItemViewHolder)holder;          itemViewHolder.mTvName.setText(mDatas.get(position));      }  }
  • 6、在Activity里面的scroll监听做上拉要执行的逻辑

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {          @Override          public void onScrollStateChanged(RecyclerView recyclerView, int newState) {              super.onScrollStateChanged(recyclerView, newState);              Log.d("test", "StateChanged = " + newState);          }          @Override          public void onScrolled(RecyclerView recyclerView, int dx, int dy) {              super.onScrolled(recyclerView, dx, dy);              Log.d("test", "onScrolled");              int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition();              if (lastVisibleItemPosition + 1 == adapter.getItemCount()) {                  Log.d("test", "loading executed");                  boolean isRefreshing = swipeRefreshLayout.isRefreshing();                  if (isRefreshing) {                      adapter.notifyItemRemoved(adapter.getItemCount());                      return;                  }                  if (!isLoading) {                      isLoading = true;                      handler.postDelayed(new Runnable() {                          @Override                          public void run() {                              mDatas.add("上拉 加载 很多数据");                              adapter.notifyDataSetChanged();                              swipeRefreshLayout.setRefreshing(false);                              adapter.notifyItemRemoved(adapter.getItemCount());                              Log.d("test", "load more completed");                              isLoading = false;                          }                      }, 1000);                  }              }          }      });

大概就是这么些步骤,,下面附上代码。

public class RefreshActivity extends AppCompatActivity {    private RecyclerView recyclerView;    private SwipeRefreshLayout swipeRefreshLayout;    boolean isLoading;    private List<String> mDatas = new ArrayList<>();    private RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, mDatas);    private Handler handler = new Handler();    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_refresh);        swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);        initView();        initData();    }    public void initView() {        swipeRefreshLayout.setColorSchemeResources(                R.color.google_blue,                R.color.google_green,                R.color.google_red,                R.color.google_yellow        );        swipeRefreshLayout.post(new Runnable() {            @Override            public void run() {                swipeRefreshLayout.setRefreshing(true);            }        });        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {            @Override            public void onRefresh() { // 下拉加载新数据                handler.postDelayed(new Runnable() {                    @Override                    public void run() {                        mDatas.add(0,"下拉刷新出来的新数据");                        adapter.notifyDataSetChanged();                        swipeRefreshLayout.setRefreshing(false);                        adapter.notifyItemRemoved(adapter.getItemCount());                    }                }, 2000);            }        });        final LinearLayoutManager layoutManager = new LinearLayoutManager(this);        recyclerView.setLayoutManager(layoutManager);        recyclerView.setAdapter(adapter);        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {            @Override            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                super.onScrollStateChanged(recyclerView, newState);                Log.d("test", "StateChanged = " + newState);            }            @Override            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                super.onScrolled(recyclerView, dx, dy);                Log.d("test", "onScrolled");                int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition();                if (lastVisibleItemPosition + 1 == adapter.getItemCount()) {                    Log.d("test", "loading executed");                    boolean isRefreshing = swipeRefreshLayout.isRefreshing();                    if (isRefreshing) {                        adapter.notifyItemRemoved(adapter.getItemCount());                        return;                    }                    if (!isLoading) {                        isLoading = true;                        handler.postDelayed(new Runnable() {                            @Override                            public void run() {                                mDatas.add("上拉 加载 很多数据");                                adapter.notifyDataSetChanged();                                swipeRefreshLayout.setRefreshing(false);                                adapter.notifyItemRemoved(adapter.getItemCount());                                Log.d("test", "load more completed");                                isLoading = false;                            }                        }, 1000);                    }                }            }        });        //添加点击事件        adapter.setOnItemClickListener(new RecyclerViewAdapter.OnItemClickListener() {            @Override            public void onItemClick(View view, int position) {                Log.d("test", "item position = " + position);            }            @Override            public void onItemLongClick(View view, int position) {            }        });    }    public void initData() {        handler.postDelayed(new Runnable() {            @Override            public void run() {                getData();            }        }, 1500);    }    /**     * 获取测试数据     */    private void getData() {        for (int i = 0; i < 20; i++) {            mDatas.add("数据  "+i);        }        adapter.notifyDataSetChanged();        swipeRefreshLayout.setRefreshing(false);        adapter.notifyItemRemoved(adapter.getItemCount());    }}

.
.
页面布局

<?xml version="1.0" encoding="utf-8"?><android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/swipeRefreshLayout"    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"        android:scrollbars="vertical"></android.support.v7.widget.RecyclerView></android.support.v4.widget.SwipeRefreshLayout>

.
.
item布局

<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:layout_marginLeft="10dp"    android:layout_marginRight="10dp"    android:layout_marginTop="6dp"    android:orientation="vertical"    app:cardBackgroundColor="@color/colorPrimary"    app:cardPreventCornerOverlap="true"    app:cardUseCompatPadding="true"    app:contentPadding="6dp">    <TextView        android:id="@+id/mTvName"        android:layout_width="match_parent"        android:layout_height="36dp"        android:gravity="center"        android:textColor="#ffffff"        android:text="你好色彩" /></android.support.v7.widget.CardView>

.
.
Adapter

public class RecyclerViewAdapter extends Adapter<ViewHolder> {    private static final int TYPE_ITEM = 0;    private static final int TYPE_FOOTER = 1;    private Context context;    private List<String> mDatas;    public RecyclerViewAdapter(Context context, List<String> mDatas) {        this.context = context;        this.mDatas = mDatas;    }    public interface OnItemClickListener {        void onItemClick(View view, int position);        void onItemLongClick(View view, int position);    }    private OnItemClickListener onItemClickListener;    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {        this.onItemClickListener = onItemClickListener;    }    @Override    public int getItemCount() {        return mDatas.size() == 0 ? 0 : mDatas.size() + 1;    }    @Override    public int getItemViewType(int position) {        if (position + 1 == getItemCount()) {            return TYPE_FOOTER;        } else {            return TYPE_ITEM;        }    }    @Override    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        if (viewType == TYPE_ITEM) {            View view = LayoutInflater.from(context).inflate(R.layout.item_base, parent,                    false);            return new ItemViewHolder(view);        } else if (viewType == TYPE_FOOTER) {            View view = LayoutInflater.from(context).inflate(R.layout.item_foot, parent,                    false);            return new FootViewHolder(view);        }        return null;    }    @Override    public void onBindViewHolder(final ViewHolder holder, int position) {        if (holder instanceof ItemViewHolder) {            if (onItemClickListener != null) {                holder.itemView.setOnClickListener(new View.OnClickListener() {                    @Override                    public void onClick(View v) {                        int position = holder.getLayoutPosition();                        onItemClickListener.onItemClick(holder.itemView, position);                    }                });                holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {                    @Override                    public boolean onLongClick(View v) {                        int position = holder.getLayoutPosition();                        onItemClickListener.onItemLongClick(holder.itemView, position);                        return false;                    }                });            }            ItemViewHolder itemViewHolder = (ItemViewHolder)holder;            itemViewHolder.mTvName.setText(mDatas.get(position));        }    }    static class ItemViewHolder extends ViewHolder {        TextView mTvName;        public ItemViewHolder(View view) {            super(view);            mTvName = (TextView) view.findViewById(R.id.mTvName);        }    }    static class FootViewHolder extends ViewHolder {        public FootViewHolder(View view) {            super(view);        }    }

九、其他

1、反序

比如服务器给我们返回一组日期从早到晚的数组,我们也用的很开心,但是突然说要降序,我们不用自己写比较器,只需要利用下面代码反序展示就好

        mLinearLayoutManager = new LinearLayoutManager(this);        // 两者一起使用,才能使得反转后从上方开始展示        mLinearLayoutManager.setReverseLayout(true);//列表翻转        mLinearLayoutManager.setStackFromEnd(true);//列表再底部开始展示,反转后由上面开始展示        rvGroupList.setLayoutManager(mLinearLayoutManager);

2、跳转到指定位置

在Adapter里面添加如下方法,需要地方调用即可

public static void moveToPosition(LinearLayoutManager manager, int position) {        manager.scrollToPositionWithOffset(position, 0);        manager.setStackFromEnd(true);    }

调用示例

 mHideMsgLogAdapter.moveToPosition(mLinearLayoutManager,messList.size()-1);


作者:阿敏其人
链接:http://www.jianshu.com/p/b4d1bfd55ae9
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。