本文转自https://blog.csdn.net/tuike/article/details/79064750#comments,用作参考学习

RecyclerView是support:recyclerview-v7中提供的控件,最低兼容到android 3.0版本。

官方介绍RecyclerView为在有限的窗口展现大量数据的控件。拥有类似功能的控件有ListView、GridView以及被Google遗弃的Gallery等,为毛已经有了它们,Google还推出RecyclerView呢,那就要说说RecyclerView所具有的一些优势了。

那RecyclerView到底有啥优势呢?总结起来六颗字:低耦合高类聚。RecyclerView已经标准化ViewHolder,我们自定义的ViewHoler需要继承 RecyclerView.ViewHolder,然后在构造方法中初始化控件,后面会有具体介绍。通过设置不同的LayoutManager,以及结合ItemDecoration , ItemAnimator,ItemTouchHelper,可以实现非常炫酷的效果,这些是ListView等控件难以企及的。

基本使用:

1.使用前需要在在gradle中添加依赖

implementation 'com.android.support:recyclerview-v7:27.0.2'

2.编写代码,首先我们需要在Xml中写RecyclerView的布局

  <android.support.v7.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent"/>

然后在activity中获取RecyclerView,并设置LayoutManager以及adapter

//通过findViewById拿到RecyclerView实例
mRecyclerView =   findViewById(R.id.recyclerView);
//设置RecyclerView管理器
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
//初始化适配器
mAdapter = new MyRecyclerViewAdapter(list);
//设置添加或删除item时的动画,这里使用默认动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//设置适配器
mRecyclerView.setAdapter(mAdapter);

下面是MyRecyclerViewAdapter的代码:

package com.sharejoys.recyclerviewdemo.actvity;import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;import com.sharejoys.recyclerviewdemo.R;import java.util.List;/*** Created by 青青-子衿 on 2018/1/15.*/public class MyRecyclerViewAdapterextends RecyclerView.Adapter<MyAdapter.ViewHolder> {private List<String> list;public MyAdapter(List<String> list) {this.list = list;}@Overridepublic MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_base_use, parent, false);MyAdapter.ViewHolder viewHolder = new MyAdapter.ViewHolder(view);return viewHolder;}@Overridepublic void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {holder.mText.setText(list.get(position));}@Overridepublic int getItemCount() {return list.size();}class ViewHolder extends RecyclerView.ViewHolder {TextView mText;ViewHolder(View itemView) {super(itemView);mText = itemView.findViewById(R.id.item_tx);}}
}

这里item_normal的布局也非常简单

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_content"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/item_tx"android:layout_width="match_content"android:layout_height="wrap_content"android:gravity="center"android:padding="10dp"android:layout_gravity="center_horizontal"android:text="Item"/></LinearLayout>

然后我们运行效果如下

从例子也可以看出来,RecyclerView的用法并不比ListView复杂,反而更灵活好用,它将数据、排列方式、数据的展示方式都分割开来,因此可定制型,自定义的形式也非常多,非常灵活。

设置横向布局:

 mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));

设置网格布局:

 mRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));

设置瀑布流:

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

如果第二个参数可以设置为横向的,则效果如下:

从以上可知,我们可以通过设置不同的管理器,实现不同的效果
LinearLayoutManager:以线性布局展示,可以设置横向和纵向
GridLayoutManager:以网格形式展示,类似GridView效果
StaggeredGridLayoutManager:以瀑布流形式的效果

RecyclerView条目之间默认没有分割线,那是否可以像ListView一样设置divider以及dividerHight搞一条分割线出来呢,答案是不可以的,google并没有提供这样的属性。但是谷歌为我们提供了可以定制的解决办法,那就是以下要说ItemDecoration

利用ItemDecoration实现条目分割线

ItemDecoration是谷歌定义的可用于画分割线的类, 是抽象的,需要我们自己去实现

  /*** An ItemDecoration allows the application to add a special drawing and layout offset* to specific item views from the adapter's data set. This can be useful for drawing dividers* between items, highlights, visual grouping boundaries and more.** <p>All ItemDecorations are drawn in the order they were added, before the item* views (in {@link ItemDecoration#onDraw(Canvas, RecyclerView, RecyclerView.State) onDraw()}* and after the items (in {@link ItemDecoration#onDrawOver(Canvas, RecyclerView,* RecyclerView.State)}.</p>*/public abstract static class ItemDecoration {public void onDraw(Canvas c, RecyclerView parent, State state) {onDraw(c, parent);}@Deprecatedpublic void onDraw(Canvas c, RecyclerView parent) {}public void onDrawOver(Canvas c, RecyclerView parent, State state) {onDrawOver(c, parent);}@Deprecatedpublic void onDrawOver(Canvas c, RecyclerView parent) {}@Deprecatedpublic void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {outRect.set(0, 0, 0, 0);}public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),parent);}}

当我们通过

mRecyclerView.addItemDecoration();

onDraw: 该方法可以在RecyclerView的画布上画任何装饰,且是在 the item views 被绘制之前回调
    onDrawOver:该方法可以在RecyclerView的画布上画任何装饰,且是在 the item views 被绘制之后回调
    getItemOffsets :可以在该方法中为the item views添加偏移量

下面我们可以就通过继承ItemDecoration为RecyclerView添加分割线。
DividerItemDecoration的代码如下:

package com.sharejoys.mvpdemo.ui.customview;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.annotation.IntDef;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;/*** Date: 2018/1/14** @author 青青-子衿* @since 1.0*/public class DividerItemDecoration extends RecyclerView.ItemDecoration {@OrientationTypeprivate int mOrientation = LinearLayoutManager.VERTICAL;private Drawable mDivider;private int[] attrs = new int[]{android.R.attr.listDivider};public DividerItemDecoration(Context context, @OrientationType int orientation) {TypedArray typedArray = context.obtainStyledAttributes(attrs);mDivider = typedArray.getDrawable(0);typedArray.recycle();setOrientation(orientation);}private void setOrientation(@OrientationType int orientation) {if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {throw new IllegalArgumentException("传入的布局类型不合法");}this.mOrientation = orientation;}@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {//调用这个绘制方法,RecyclerView会回调该绘制方法,需要我们自己去绘制条目的间隔线if (mOrientation == LinearLayoutManager.VERTICAL) {//垂直drawVertical(c, parent);} else {//水平drawHorizontal(c, parent);}}private void drawVertical(Canvas c, RecyclerView parent) {// 画水平线int left = parent.getPaddingLeft();int right = parent.getWidth() - parent.getPaddingRight();int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {View child = parent.getChildAt(i);RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();int top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));int bottom = top + mDivider.getIntrinsicHeight();mDivider.setBounds(left, top, right, bottom);mDivider.draw(c);}}private void drawHorizontal(Canvas c, RecyclerView parent) {int top = parent.getPaddingTop();int bottom = parent.getHeight() - parent.getPaddingBottom();int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {View child = parent.getChildAt(i);RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();int left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));int right = left + mDivider.getIntrinsicHeight();mDivider.setBounds(left, top, right, bottom);mDivider.draw(c);}}@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {//获得条目的偏移量(所有的条目都会回调一次该方法)if (mOrientation == LinearLayoutManager.VERTICAL) {//垂直outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());} else {//水平outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);}}@IntDef({LinearLayoutManager.VERTICAL, LinearLayoutManager.HORIZONTAL})public @interface OrientationType {}
}

然后在activity设置水平方向

mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));


竖直方向:

mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONAL, false);
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.HORIZONAL))

这里的分割线是默认的,我们可以在主题中去设置分割线的颜色

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

bg_recyclerview_divider.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><gradientandroid:centerColor="#ff00ff00"android:endColor="#ff0000ff"android:startColor="#ffff0000"android:type="linear"/><sizeandroid:width="10dp"android:height="10dp"/></shape>

运行后效果如下

以上的分割线只适用在LinearLayoutManager的相关布局中。
对于GridLayoutManager布局是不适用的。需要我们单独写一个。

以下是对于GridLayoutManager布局的分割线代码

package com.sharejoys.recyclerviewdemo.view;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.view.View;/*** Date: 2018/1/14 ** @author 青青-子衿* @since 1.0*/public class DividerGridViewItemDecoration extends RecyclerView.ItemDecoration {private Drawable mDivider;private int[] attrs = new int[]{android.R.attr.listDivider};public DividerGridViewItemDecoration(Context context) {TypedArray typedArray = context.obtainStyledAttributes(attrs);mDivider = typedArray.getDrawable(0);typedArray.recycle();}@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {drawVertical(c, parent);drawHorizontal(c, parent);}private void drawVertical(Canvas c, RecyclerView parent) {//绘制垂直间隔线(垂直的矩形)int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {View child = parent.getChildAt(i);RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();int left = child.getRight() + params.rightMargin;int right = left + mDivider.getIntrinsicWidth();int top = child.getTop() - params.topMargin;int bottom = child.getBottom() + params.bottomMargin;mDivider.setBounds(left, top, right, bottom);mDivider.draw(c);}}private void drawHorizontal(Canvas c, RecyclerView parent) {//绘制水平分割线int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {View child = parent.getChildAt(i);RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();int left = child.getLeft() - params.leftMargin;int right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth();int top = child.getBottom() + params.bottomMargin;int bottom = top + mDivider.getIntrinsicHeight();mDivider.setBounds(left, top, right, bottom);mDivider.draw(c);}}@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {// 四个方向的偏移值int right = mDivider.getIntrinsicWidth();int bottom = mDivider.getIntrinsicHeight();RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();int itemPosition = params.getViewAdapterPosition();if (isLastColum(itemPosition, parent)) {right = 0;}if (isLastRow(itemPosition, parent)) {bottom = 0;}outRect.set(0, 0, right, bottom);}/*** 是否最后一行*/private boolean isLastRow(int itemPosition, RecyclerView parent) {int spanCount = getSpanCount(parent);if (spanCount != -1) {int childCount = parent.getAdapter().getItemCount();int lastRowCount = childCount % spanCount;//最后一行的数量小于spanCountif (lastRowCount == 0 || lastRowCount < spanCount) {return true;}}return false;}/*** 根据parent获取到列数*/private int getSpanCount(RecyclerView parent) {RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();if (layoutManager instanceof GridLayoutManager) {GridLayoutManager lm = (GridLayoutManager) layoutManager;int spanCount = lm.getSpanCount();return spanCount;}return -1;}/*** 判断是否是最后一列*/private boolean isLastColum(int itemPosition, RecyclerView parent) {int spanCount = getSpanCount(parent);if (spanCount != -1) {if ((itemPosition + 1) % spanCount == 0) {return true;}}return false;}
}

我们在activity中使用该分割线

        mRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));mRecyclerView.addItemDecoration(new DividerGridViewItemDecoration(this));

点击事件

RecyclerView并没有像ListView的那样可以设置点击事件以及长按点击事件,这个需要我们可以在adapter中去设置回调的方式实现,具体代码如下:
MyRecyclerViewAdapter的代码如下:

package com.sharejoys.recyclerviewdemo.actvity;import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;import com.sharejoys.recyclerviewdemo.R;import java.util.List;/*** Created by 青青-子衿 on 2018/1/15.*/public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {private List<String> list;private OnItemClickListener onItemClickListener;private OnItemLongClickListener onItemLongClickListener;/*** 设置点击事件*/public void setOnItemClickListener(OnItemClickListener onItemClickListener) {this.onItemClickListener = onItemClickListener;}/*** 设置长按点击事件*/public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {this.onItemLongClickListener = onItemLongClickListener;}public MyRecyclerViewAdapter(List<String> list) {this.list = list;}@Overridepublic MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_base_use, parent, false);MyRecyclerViewAdapter.ViewHolder viewHolder = new MyRecyclerViewAdapter.ViewHolder(view);return viewHolder;}@Overridepublic void onBindViewHolder(MyRecyclerViewAdapter.ViewHolder holder, int position) {holder.mText.setText(list.get(position));int adapterPosition = holder.getAdapterPosition();if (onItemClickListener != null) {holder.itemView.setOnClickListener(new MyOnClickListener(position, list.get(adapterPosition)));}if (onItemLongClickListener != null) {holder.itemView.setOnLongClickListener(new MyOnLongClickListener(position, list.get(adapterPosition)));}}@Overridepublic int getItemCount() {return list.size();}class ViewHolder extends RecyclerView.ViewHolder {TextView mText;ViewHolder(View itemView) {super(itemView);mText = itemView.findViewById(R.id.item_tx);}}private class MyOnLongClickListener implements View.OnLongClickListener {private int position;private String data;public MyOnLongClickListener(int position, String data) {this.position = position;this.data = data;}@Overridepublic boolean onLongClick(View v) {onItemLongClickListener.onItemLongClick(v, position, data);return true;}}private class MyOnClickListener implements View.OnClickListener {private int position;private String data;public MyOnClickListener(int position, String data) {this.position = position;this.data = data;}@Overridepublic void onClick(View v) {onItemClickListener.onItemClick(v, position, data);}}public interface OnItemClickListener {void onItemClick(View view, int position, String data);}public interface OnItemLongClickListener {void onItemLongClick(View view, int position, String data);}}

运行后效果如下:

ItemAnimator

我们可以为RecyclerView设置增加和删除动画,这里我们可以使用默认动画

//设置添加或删除item时的动画,这里使用默认动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());

然后在Adapter中增加删除和添加数据的方法

   /*** 插入一条数据** @param index 下标* @param s     数据*/public void addItem(int index, String s) {list.add(index, s);notifyItemInserted(index);}/*** 删除一条数据** @param index 下标*/public void deleteItem(int index) {list.remove(index);notifyItemRemoved(index);}

activty调用删除和添加方法后效果如下

RecycleView还有一些其他用法,比如结合ItemTouchHelper实现item的拖拽效果,可以自定义增加header和footer(类似Listview),有时间我就会补上!

最后附上demo地址

RecyclerView详细用法相关推荐

  1. C# SqlSugar框架的学习使用(五)-- 更新和删除数据的详细用法

    前言 上一篇<C# SqlSugar框架的学习使用(四)-- 插入数据的详细用法>我们已经把SqlSugar的插入多种用法实现了,这篇我们就来说说更新数据和删除数据的多种用法.我们就用上一 ...

  2. Android命令行工具logcat详细用法!

    logcat是Android中一个命令行工具,可以用于得到程序的log信息. 见板凳详细说明!      本贴内容来自网络,引用网址为:http://hi.baidu.com/%C9%C1%D2%AB ...

  3. __declspec关键字详细用法

    __declspec关键字详细用法 2009-01-21 16:23 __declspec用于指定所给定类型的实例的与Microsoft相关的存储方式.其它的有关存储方式的修饰符如static与ext ...

  4. mysql left/right join算法效率分析_mysql left join,right join,inner join超详细用法分析

    MySQL left join,right join,inner join超详细用法分析 下面是例子分析 表A记录如下: aID        aNum 1           a20050111 2 ...

  5. python sort怎么用,Linux Sort命令详细用法(有实例)

    Linux Sort命令详细用法(有实例) sort是在Linux里非常常用的一个命令,管排序的,集中精力,五分钟搞定sort,现在开始! Linux sort命令进阶: 1 sort的工作原理 so ...

  6. vue性能优化-------vendor优化详细用法(瘦身),减小体积,引入cdn

    vue性能优化-------vendor优化详细用法(瘦身),减小体积,引入cdn 原创ChrisWang_ 最后发布于2019-05-24 10:25:58 阅读数 1332  收藏 展开 vue性 ...

  7. oracle rtrim(),Oracle ltrim() rtrim() 函数详细用法

    嘿嘿,今天在论坛里看了一篇帖子,讨论ltrim() 函数的详细用法,下面我借几个高手的回答总结一下: 先看几个实例: SQL> select ltrim('109224323','109') f ...

  8. pythonrange函数用法_python range()函数详细用法

    python range()函数详细用法 函数原型:range(start, end, scan): 参数含义:start:计数从start开始.默认是从0开始.例如range(5)等价于range( ...

  9. python中3 and not 5_python中not、and和or的优先级与详细用法介绍

    前言 (小白专用)本次所分享的是Python中的not.and.or的执行时的优先级,以及他们的具体用法.本文比较详细,不喜勿喷. 一.not.and.or的含义以及优先级 对象 返回结果 优先顺序 ...

最新文章

  1. JavaScript的Generator理解使用
  2. 迁移pg_PG奥斯卡!云数据库专属集群MyBase荣获2020 PG亚洲大会“年度最佳产品奖”...
  3. 基于python的文件加密传输系统 毕业论文_20183411 李丞灏 2020-2021 《python程序设计》 实验三 加密传输文件 实验报告...
  4. 解决Windows资源管理器右键菜单打开EditPlus容易导致资源管理器无响应问题
  5. crsctl stop crs 与 crsctl stop resources的区别
  6. Oracle的云计算模式
  7. ssis 链接mysql_SSIS 连接数据
  8. 华为p10 内存测试软件,华为p10闪存门怎么回事 华为p10/P10Plus闪存怎么测试
  9. 没有稿酬,混了这么多年-文艺it工程师自白(写于2014年)
  10. 怎么把数据文件上传云服务器,如何将数据上传到云服务器上
  11. logd 删除log
  12. 2020年南京大学计算机系九推面试
  13. 安装宝塔后手动安装php,宝塔 安装 php扩展步骤
  14. Entity Framework Core 之Modeling Relationships
  15. Cannot read lifecycle mapping metadata for artifact org.apache.maven.plugins:mav问题
  16. 浅谈当前互联网就业形势
  17. 除了百度、搜狗搜索你还知道哪些好用的搜索引擎吗?
  18. wget 递归下载整个网站
  19. 华为hcie考试费用多少钱
  20. 微信第三方登录——JAVA后台

热门文章

  1. 小鼠内皮细胞分离提取方法
  2. css3教程3-边框圆角:四叶草
  3. Springboot整合SAPJCO采坑
  4. ESP32 单片机学习笔记 - 05 - AP/Smart Config
  5. Mysql的when then_mysql case when then 使用
  6. openapi java_openapi-demo-java-master
  7. 判断电话号码对应字母组合数
  8. Android基础篇-多线程下载(一)
  9. VMware虚拟机安装Linux系统
  10. 街机风 Tappy Chicken(官方)材质