虽然RecyclerView出现已经有一段时间了,但是还是想要自己总结一下,总的来说其基本使用方法:
你想要控制其显示的方式,请通过布局管理器LayoutManager;
你想要控制Item间的间隔(可绘制),请通过ItemDecoration;
你想要控制Item增删的动画,请通过ItemAnimator;
你想要控制点击、长按事件,不好意思你得自己写喽;

鉴于我们对于ListView的使用特别的熟悉,对比下RecyclerView的使用代码:

我添加的依赖是:compile 'com.android.support:recyclerview-v7:24.0.0+'

//RecyclerView的三种常用Manager
mRecyclerView = findView(R.id.id_recyclerview);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, OrientationHelper.HORIZONTAL, false);
GridLayoutManager   gridLayoutManager = new GridLayoutManager(this, 3, OrientationHelper.VERTICAL, false);
StaggeredGridLayoutManager sglm = newGridLayoutManager和StaggeredGridLayoutManager(4, OrientationHelper.VERTICAL);
mRecyclerView.setLayoutManager(gridLayoutManager);//设置布局管理器

mRecyclerView.setAdapter(adapter);  //设置adapter

mRecyclerView.setItemAnimator(new DefaultItemAnimator());//添加默认Item增删动画而非初始化时的动画

//添加分割线

mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(),DividerItemDecoration.HORIZONTAL_LIST));

RecyclerView的分割线的设置:
RecyclerView只管回收与复用View,其他的你可以自己去设置。可以看出其高度的解耦,而且RecyclerView并没有像ListView一样有divide属性,

RecyclerView的分割线需要自己去设置,首先需要准备一个分割线类来实现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(Rect outRect, View view, RecyclerView parent, State state) {getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),parent);
}@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {outRect.set(0, 0, 0, 0);}

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

  • onDraw方法先于drawChildren
  • onDrawOver在drawChildren之后,一般我们选择复写其中一个即可。
  • getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator。

接下来我们看一个RecyclerView.ItemDecoration的实现类,该类很好的实现了RecyclerView添加分割线,我们先来看使用LinearLayoutManager时定义的分割线实现类:

/*** 描述:该类用于RecyclerView采用LinearLayoutManager时的分割线设置*/
public class RecycleLinearItemDecoration extends RecyclerView.ItemDecoration {/*** android.R.attr.listDivider:这是系统自带的分割线,可以找到Application theme,在theme中* 添加<item name="android:listDivider">@drawable/divider_bg</item>来设计自己的分割线* */private  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 RecycleLinearItemDecoration(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;}@Overridepublic void onDraw(Canvas c, RecyclerView parent) {  //系统自带Canvasif (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++) { //注意这里的childCount是否需要-1final View child = parent.getChildAt(i);final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();final int top = child.getBottom() + params.bottomMargin;//item的下边开始设置分割线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++) { //注意这里的childCount是否需要-1final View child = parent.getChildAt(i);final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();final int left = child.getRight() + params.rightMargin; //item的右边开始设置分割线final int right = left + mDivider.getIntrinsicHeight();mDivider.setBounds(left, top, right, bottom);mDivider.draw(c);}}@Overridepublic void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {if (mOrientation == VERTICAL_LIST) {//通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator,Intrinsic:固有的outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());} else {outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);}}
}

该实现类可以看到通过读取系统主题中的 Android.R.attr.listDivider作为Item间的分割线,并且支持横向和纵向。如果你不清楚它是怎么做到的读取系统的属性用于自身,请参考我的另一篇博文:Android 深入理解Android中的自定义属性

我们在原来的代码中添加一句:

mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));
  • 1
  • 2
  • 1
  • 2

ok,现在再运行,就可以看到分割线的效果了。

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

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

然后自己写个drawable即可,下面我们换一种分隔符:

<?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" /><size android:height="4dp"/></shape>

再来让我们看下GridLayoutManager时定义的分割线实现类(因为这里每个item需要四条分割线,所以需要重定义):

/*** 描述:该类用于RecyclerView采用GridLayoutManager和StaggeredGridLayoutManager时的分割线设置*/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();}@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.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();int spanCount = getSpanCount(parent);for (int i = 0; i < childCount; i++) {if(isLastRaw(parent, i, spanCount, childCount)) {continue;}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;}@Overridepublic 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());}}
}

为了能够看明白,我直接把Activity中的代码都粘过来吧,不过其中还有下边要讲的Item增删动画,也一起贴出来了:

public class RecyclerViewActivity extends BaseActivity implements Toolbar.OnMenuItemClickListener {@Bind(R.id.recyclerview)RecyclerView recyclerview;@Bind(R.id.swipe_recycle_lt)SwipeRefreshLayout swipeRecycleLt;private RecycleBean bean;private List<Integer> contentListT;private String[] titles;private ArrayList<Boolean> contentListCBox;private ReAdapter reAdapter;@Overrideprotected void initView() {//Toobar的使用需要先fvb到Toobar布局,然后在MenuInflate到menu布局,同时给toobar设置点击监听Toolbar toolBar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(toolBar);toolBar.setTitle("ToolBarTitle");//设置标题
//        toolBar.setNavigationIcon(R.mipmap.ic_launcher);//设置图标
//        toolBar.addView(view);toolBar.setOnMenuItemClickListener(this);//设置Menu Item点击}@Overrideprotected void initData() {swipeRecycleLt.setColorSchemeColors(Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW);bean = new RecycleBean();contentListT = new ArrayList<Integer>();contentListCBox = new ArrayList<Boolean>();titles = new String[160];for (int i = 0; i < 111; i++) {contentListT.add(i);titles[i] = "我是title: " + i;contentListCBox.add(false);}bean.contentListCBox = contentListCBox;bean.contentListT = contentListT;bean.titles = titles;LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, OrientationHelper.HORIZONTAL, false);GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3, OrientationHelper.VERTICAL, false);
//        StaggeredGridLayoutManager sglm = new StaggeredGridLayoutManager(this, null, 4, StaggeredGridLayoutManager.GAP_HANDLING_NONE, StaggeredGridLayoutManager.VERTICAL);StaggeredGridLayoutManager sglm = new StaggeredGridLayoutManager(4, OrientationHelper.VERTICAL);
//        recyclerview.addItemDecoration( new RecycleLinearItemDecoration(this, OrientationHelper.HORIZONTAL)); recyclerview.addItemDecoration(new DividerGridItemDecoration(this)); //添加分割线recyclerview.setItemAnimator(new DefaultItemAnimator());   //添加默认Item动画reAdapter = new ReAdapter(this, bean);recyclerview.setLayoutManager(sglm);recyclerview.setHasFixedSize(true); //保存item尺寸值,以便不在测量recyclerview.setAdapter(reAdapter);}@Overridepublic int getContentId() {return R.layout.recyclerviewtext;}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ButterKnife.bind(this);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main, menu);return super.onCreateOptionsMenu(menu);}//    @Override
//    public boolean onOptionsItemSelected(MenuItem item) {
//        Log.d("onOptionsItemSelected", "run");
//        switch (item.getItemId()) {
//            case R.id.acitonbar_add_menu:
//                reAdapter.addData(1);
//                break;
//            case R.id.acitonbar_delate_menu:
//                reAdapter.removeData(1);
//                break;
//        }
//        return true;
//    }@Overridepublic boolean onMenuItemClick(MenuItem item) {Log.d("onMenuItemClick", "run");switch (item.getItemId()) {case R.id.acitonbar_add_menu:reAdapter.addData(1);break;case R.id.acitonbar_delate_menu:reAdapter.removeData(1);break;}return true;}
}

分割线说完了,下面就浅谈一下条目增删动画吧,这里先借助默认的实现,当Item添加和移除的时候,添加动画效果就很简单了:

// 设置item动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
  • 1
  • 2
  • 1
  • 2

系统为我们提供了一个默认的实现,我们为我们的瀑布流添加以上一行代码,效果为:

这里需要注意,更新数据集不是用adapter.notifyDataSetChanged()而是 notifyItemInserted(position)notifyItemRemoved(position),否则没有动画效果。 
上述为adapter中添加了两个方法:

public void addData(int position) {mDatas.add(position, "Insert One");notifyItemInserted(position);}public void removeData(int position) {mDatas.remove(position);notifyItemRemoved(position);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Activity中点击MenuItem触发:

    @Overridepublic boolean onCreateOptionsMenu(Menu menu){getMenuInflater().inflate(R.menu.main, menu);return super.onCreateOptionsMenu(menu);}@Overridepublic boolean onOptionsItemSelected(MenuItem item){switch (item.getItemId()){case R.id.id_action_add:mAdapter.addData(1);break;case R.id.id_action_delete:mAdapter.removeData(1);break;}return true;}

额外部分:因为系统没有提供ClickListener和LongClickListener,不过我们也可以自己去添加,如下:

class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.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;}@Overridepublic void onBindViewHolder(final MyViewHolder holder, final int position){holder.tv.setText(mDatas.get(position));// 如果设置了回调,则设置点击事件if (mOnItemClickLitener != null){holder.itemView.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v){int pos = holder.getLayoutPosition();mOnItemClickLitener.onItemClick(holder.itemView, pos);}});holder.itemView.setOnLongClickListener(new OnLongClickListener(){@Overridepublic boolean onLongClick(View v){int pos = holder.getLayoutPosition();mOnItemClickLitener.onItemLongClick(holder.itemView, pos);return false;}});}}
}

Activity中去设置监听:

 mAdapter.setOnItemClickLitener(new OnItemClickLitener(){@Overridepublic void onItemClick(View view, int position){Toast.makeText(HomeActivity.this, position + " click",Toast.LENGTH_SHORT).show();}@Overridepublic void onItemLongClick(View view, int position){Toast.makeText(HomeActivity.this, position + " long click",Toast.LENGTH_SHORT).show();mAdapter.removeData(position);}});

参考资料
Android 自定义RecyclerView 实现真正的Gallery效果

A First Glance at Android’s RecyclerView
https://github.com/gabrielemariotti/RecyclerViewItemAnimators

RecyclerView 分割线和 Item默认增删动画相关推荐

  1. recyclerview item动画_RecyclerView 的 Item 酷炫动画,效果加案例讲解!

    Caner Gures | 作者依然范特西稀 | 译者技术最TOP(ID:Tech-Android) | 来源 在完成 app 的编码之后,对于一个要求美观的现代 App 来说,仅仅实现功能是不够的, ...

  2. Android添加item动画,RecyclerView基础篇-Item添加动画

    Android_Banner.jpg 简介 本节中我们介绍下给RecyclerView中的Item添加动画. 添加的动画,分为,在打开列表时有Item的展示动画,当滑动的时候没有动画 和打开列表滑动时 ...

  3. Android开发RecyclerView刷新后item里面控件动画

    项目中有个列表的item中有点赞动画,之前我用的列表框架是继承listview的,动画用起来一点问题都没有,现在列表框架是继承用的recyclerView,动画就卡主,百思不得其姐. 解决方法: 1. ...

  4. Android 活用RecyclerView分割线

    1.ItemDecoration简介 Recyclerview是我们日常开发中使用频率比较高的的控件,而其中的ItemDecoration作为布局装饰又能很方便的帮助我们定义分割线,列表排行效果以及设 ...

  5. RecyclerView分割线的技巧

    RecyclerView分割线的技巧 真的很简单,因为方法别人都已经写好了,不多说了还是看源码: package com.xiayiye.yhsh.recyclerviewdemo;import an ...

  6. RecyclerView之使用ItemTouchHelper实现交互动画

    一.简述 RecyclerView默认就有item动画,例如在增加或删除item时,都会有一个条目间位移的动画,但本文要说的不是这个!!!本文的主角是v7包中的ItemTouchHelper,它跟Re ...

  7. RecyclerView分割线

    闲来无事,把自己弄的一个RecyclerView分割线,整理一下,贴上来,当做笔记,方便自己以后查看. 使用方法: 一.添加默认分割线:默认纵向布局.高度为2.灰色, rv.addItemDecora ...

  8. 高仿支付宝增加减少item功能和动画效果

    闲来无事,看了下支付宝App做的应用item效果,很炫,效果如下: 自己实现的效果如下: gif可能有点卡,但是实现了支付宝效果, 说下思路:下面是实例图(凑合看吧,大概意思是) 开始是打算用Scro ...

  9. 万能RecyclerView分割线扩展

    该万能分割线参考自博客:RecyclerView的万能分割线_pengkv的博客-CSDN博客_android recyclerview 分割线 在他的基础上添加了距离左右边距的属性. recycle ...

最新文章

  1. web前端开发培训有哪些学习阶段
  2. 字符串-字符串反转(双指针)
  3. css编写要注意什么 及一些公用的样式和外部引用 转码
  4. 正则表达式处理的基本步骤
  5. 大学计算机基础课程报告python-Python程序设计习题解析(大学计算机基础教育规划教材)...
  6. 【算法】Logistic regression (逻辑回归) 概述
  7. 嗅觉计算机应用,重磅!美国科技巨头宣布!计算机终于有了“嗅觉”了!
  8. 电脑系统越来越慢,怎么删除临时文件
  9. 需求说明 用户登陆功能的实现 c#
  10. 【汇编语言与计算机系统结构笔记02】整数的计算机表示与运算,C中的无符号字符(unsigned)和带符号字符(signed),补码,一些例题
  11. 剑指offer面试题21. 调整数组顺序使奇数位于偶数前面(双指针)
  12. 解决AD不能复制粘贴
  13. 轨迹规划-二次规划QP
  14. 扩展YouTube视频频道,提高业务增量
  15. Thinkpad E430c 16GB内存安装成功
  16. 圆的内接正n边形的周长
  17. 图像处理零件尺寸测量matlab,题目基于数字图像处理技术的零件几何尺寸测量.doc...
  18. CSTC-2017-Web-writeup
  19. 全免费、保姆级Eclipse32位软件、安装、运行一条龙记录
  20. 【移动开发】View的scrollTo()和scrollBy()区别

热门文章

  1. 怎么取消苹果手机自动续费_怎么取消腾讯视频自动续费
  2. 关于大数据技术原理与应用的学习(5)
  3. 1900-2100公历年以查表方式取农历二十四节气(VBA)
  4. 计算机上的符号并不代表分数,你忽视的小小符号,决定着大大的分数!
  5. 【王喆-推荐系统】线上服务篇-(task1)线上高并发的推荐服务
  6. 如何比较两幅图的相似度
  7. [南京大学2022操作系统-蒋炎岩-P1] 笔记 - 操作系统概述
  8. java将汉字转成拼音首字母大写字母_java 根据汉字生成拼音全拼或拼音首字母的示例...
  9. Nu-LB-NUC140 LCD uc1601 整理
  10. 木瓜移动跨境电商SaaS 聚焦核心用户的核心需求场景