学习目标

熟悉使用 BRVAH 解决对应各种 adapter 需求

概述

BRVAH 是 Github 上的一个很棒的开源项目,主要作用是帮助我们更加高效的使用 Recyclerview 控件,处理项目中常见需求的 Adapter,使用起来非常方便,更多介绍可去BRVAH官网查看。

BRVAH 主要是针对 Adapter 来设计的。

BRVAH 为我们提供了一般情况下的BaseQuickAdapter,和几个特定需求下的Adapter,BaseMultiItemQuickAdapter用于复杂类布局列表;BaseItemDraggableAdapter 用于拖拽移动和滑动删除类列表; BaseSectionQuickAdapter用于带 Section 头部 View 的列表。

build.gradle 配置说明

添加资源库

allprojects {repositories {...maven { url "https://jitpack.io" }}
}

添加依赖

dependencies {compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:VERSION_CODE'
}

VERSION_CODE的最新版本可以参考这里。

功能概要说明

1. 实现Recyclerview的列表加载动画效果

我们只需将自建的 xxAdapter 继承 BRVAH 对应满足需求的 Adapter,然后在 Activity 中实例化,通过openLoadAnimation() 方法完成特定的动画效果。

BRVAH 支持 5 种动画,BaseQuickAdapter.ALPHAIN淡入、BaseQuickAdapter.SLIDEIN_BOTTOM从底部入、BaseQuickAdapter.SLIDEIN_LEFT从左边进入、BaseQuickAdapter.SLIDEIN_RIGHT从右边进入和自定义动画。

关于自定义的动画,可以通过实现 BaseAnimation 这个类,重写
getAnimators(View view) 方法来完成自定义动画。

2. 实现Recyclerview的复杂布局列表

在实际应用中经常会遇到各种样式的列表、宫格和列表同时存在、分类列表等情况。

2.1 Recyclerview 多样式 item 排列的效果

对于多样式的列表,根据需求创建 type 实体类实现 MultiItemEntity。 xxAdapter继承 BaseMultiItemQuickAdapter类,在构造方法中调用addItemType ()方法加入定义的 itemType 和对应布局,在 Activity 中实例化即可。

2.2 Recyclerview 宫格和列表的混排样式

关于 Grid 和 List 的混排样式,Grid 样式是一行有多个,而 List 样式是一行只有一个。我们可以把 List 样式看成是 Grid 样式,它就相当于把一个 Grid 的 item 拉长了的样子。

列表与网格混排的布局效果,我们可以创建 xxAdapter 继承 BaseMultiItemQuickAdapter 添加对应 item 类型的布局文件,在 Activity 中创建 GridLayoutManager 对象,设置 spanSize 属性,通过 Adapter 的 setSpanSizeLookup 方法设置每种 item 类型对应的 spanSize。设置 Recyclerview 的 addItemDecoration() 方法设置添加分割线或设置 item 间距。

代码片段:

...
gridLayoutManager = new GridLayoutManager(this,3);mRecyclerView.setLayoutManager(gridLayoutManager);mAdapter = new GridManagerAdapter(getDataType());// 设置横跨度// 1:就是横跨1/3// 2:就是横跨2/3// 3:就是横跨一整行mAdapter.setSpanSizeLookup(new BaseQuickAdapter.SpanSizeLookup() {@Overridepublic int getSpanSize(GridLayoutManager gridLayoutManager, int position) {return getDataType().get(position).getSpanSize();}});mRecyclerView.setAdapter(mAdapter);mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {super.getItemOffsets(outRect, view, parent, state);GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams)view.getLayoutParams();int spanSize = layoutParams.getSpanSize();int spanIndex = layoutParams.getSpanIndex();// 从左到右 0~if (spanSize == gridLayoutManager.getSpanCount()) {outRect.top = 20;}}});// 假设数据private List<MultipleItem> getDataType() {int type = 0;for (int i = 0;i < 13;i++) {if (i < 9) {type = 1;}  else {type = 2;}types.add(i,type);}List<MultipleItem> list = new ArrayList<>();for (int j = 0;j < types.size();j++) {if (types.get(j) == 1) {list.add(new MultipleItem(1,1));} else if (types.get(j) == 2) {list.add(new MultipleItem(2,3));}}return list;}
...

在创建 GridLayoutManager 对象时,有一个 spanSize 的参数需要设置,它的作用就是使原来一个 item 占满一行变为可以最多三个 item 占满一行。

而设置 setSpanSizeLookup()方法返回的是对应每种 item 类型返回具体的横跨大小。比如上面代码中 TYPE_GRID 类型的 item 在设置的 spanSize 是 1,而 GridLayoutManager 设置的 spanSize 是 3,那么该类型的 item 就会以 3 个 item 占满一行,相当于每个 item 占一行的 1/3。

在我们使用 addItemDecoration() 添加分割线的方法中对这种混排的列表设置 item 间距的时候,在 getItemOffsets() 方法里,通过 GridLayoutManager.LayoutParams 获取 spanSize 来确定 item 类型设置对应间距,其中 spanIndex 表示当前行 item 对应的下标位置,从左到右依次从 0 开始。

2.3 Recyclerview 嵌套 Recyclerview 的复杂布局

简单的分析下上图的界面布局样式,最外面一个RecyclerView,它里面的每个 item 的布局样式,最上面用 Banner 轮播图控件,下面是各种样式 item 列表的形式,其中有一个可左右滑动的 item,它是嵌套的一个 RecyclerView。

使用 BaseMultiItemQuickAdapter 在重写的 convert() 方法中实例化子 Recyclerview,同样的步骤在进行子 Recyclerview 设置,需要注意的是Recyclerview 嵌套 Recyclerview 会出现子 Recyclerview 抢焦点的问题,导致界面顶部部分控件被挤出,只需在最外面的 Recyclerview 的包裹容器中设置属性 android:descendantFocusability="blocksDescendants" 即可。通过 BRVAH 的 addHeaderView() 方法设置头部布局。

代码片段:

@Overrideprotected void convert(BaseViewHolder helper, MultiItemEntity item) {switch (helper.getItemViewType()) {...case MultipleItem.DOUBANTIME:RecyclerView recyclerView = helper.getView(R.id.recyclerview_item_view);recyclerView.setLayoutManager(new LinearLayoutManager(mContext,LinearLayoutManager.HORIZONTAL,false));recyclerView.setHasFixedSize(true);recyclerView.setAdapter(new RrecyclerViewAdapter(DataServer.getReItemData()));break;}}

2. 实现Recyclerview拖拽滑动删除

添加 RecyclerView 的拖拽和滑动移除很简单,只需 xxAdapter 继承 BaseItemDraggableAdapter 类,在 Activity 中,添加 OnItemDragListenerOnItemSwipeListener 两个接口,通过 xxAdapter 配置基本属性即可。

代码片段:

OnItemDragListener listener = new OnItemDragListener() {@Overridepublic void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos) {// item 拖拽的起始位置Log.d(TAG,"drag start");}@Overridepublic void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to) {// item 拖拽的过程位置变化Log.d(TAG, "move from: " + source.getAdapterPosition() + " to: " + target.getAdapterPosition());}@Overridepublic void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos) {// item 拖拽的终点位置Log.d(TAG, "drag end");}};OnItemSwipeListener onItemSwipeListener = new OnItemSwipeListener() {@Overridepublic void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int pos) {// item 滑动的起始位置Log.d(TAG, "view swiped start: " + pos);}@Overridepublic void clearView(RecyclerView.ViewHolder viewHolder, int pos) {// item 滑动后的恢复位置Log.d(TAG, "View reset: " + pos);}@Overridepublic void onItemSwiped(RecyclerView.ViewHolder viewHolder, int pos) {// item 滑动的移除位置Log.d(TAG, "View Swiped: " + pos);}@Overridepublic void onItemSwipeMoving(Canvas canvas, RecyclerView.ViewHolder viewHolder,float dX, float dY, boolean isCurrentlyActive) {// item 滑动的过程canvas.drawColor(ContextCompat.getColor(ItemDragAndSwipUseActivity.this,R.color.colorKbtt));}};
ItemDragAndSwipeCallback itemDragAndSwipeCallback = new ItemDragAndSwipeCallback(mAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemDragAndSwipeCallback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);mItemDragAndSwipeCallback.setSwipeMoveFlags(ItemTouchHelper.START | ItemTouchHelper.END);// open slide to deletemAdapter.enableSwipeItem();mAdapter.setOnItemSwipeListener(onItemSwipeListener);// open dragmAdapter.enableDragItem(itemTouchHelper);mAdapter.setOnItemDragListener(listener);mRecyclerView.setAdapter(mAdapter);

3. 实现Recyclerview监听事件

BRVAH为我们提供好了全面的 item 和 item 子 View 的监听事件,我们只需在继承 BRVAH 提供的 Adapter 的基础上,通过 xxAdapter 来调用对应的监听,只是设置监听子 View 前,我们需要在 xxAadapter 中对应的 item 的子 View 注册对应的监听事件。

3.1 对于 item 的监听事件处理

直接在 Activity 中添加
item 点击事件

adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {@Overridepublic void onItemClick(BaseQuickAdapter adapter, View view, int position) {Log.d(TAG, "onItemClick: ");Toast.makeText(ItemClickActivity.this, "onItemClick" + position, Toast.LENGTH_SHORT).show();}});

item 长按监听事件

adapter.setOnItemLongClickListener(new BaseQuickAdapter.OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(BaseQuickAdapter adapter, View view, int position) {Log.d(TAG, "onItemLongClick: ");Toast.makeText(ItemClickActivity.this, "onItemLongClick" + position, Toast.LENGTH_SHORT).show();return false;}});

3.2 对 item 中子 View 的监听事件处理

首先需要在 xxAdapter 中注册子 View 的监听事件。
点击监听事件

 @Overrideprotected void convert(BaseViewHolder viewHolder, Status item) {viewHolder.setText(R.id.tweetName, item.getUserName()).setText(R.id.tweetText, item.getText()).setText(R.id.tweetDate, item.getCreatedAt()).setVisible(R.id.tweetRT, item.isRetweet()).addOnClickListener(R.id.tweetAvatar).addOnClickListener(R.id.tweetName).linkify(R.id.tweetText);}

长按监听事件

 @Overrideprotected void convert(BaseViewHolder helper, Status item) {helper.setText(R.id.tweetName, item.getUserName()).setText(R.id.tweetText, item.getText()).setText(R.id.tweetDate, item.getCreatedAt()).setVisible(R.id.tweetRT, item.isRetweet()).addOnLongClickListener(R.id.tweetText).linkify(R.id.tweetText);}

然后在 Activity 中设置对应的子 View 监听事件
点击事件

adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {@Overridepublic boolean onItemChildClick(BaseQuickAdapter adapter, View view, int position) {Log.d(TAG, "onItemChildClick: ");Toast.makeText(ItemClickActivity.this, "onItemChildClick" + position, Toast.LENGTH_SHORT).show();return false;}});

子 View 长按事件

adapter.setOnItemChildLongClickListener(new BaseQuickAdapter.OnItemChildLongClickListener() {@Overridepublic void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) {Log.d(TAG, "onItemChildLongClick: ");Toast.makeText(ItemClickActivity.this, "onItemChildLongClick" + position, Toast.LENGTH_SHORT).show();}});

4. 实现Recyclerview 刷新

列表下拉刷新和上拉加载是最常用的,BRVAH 虽然也提供了刷新功能,但只是上拉加载更多,而且样式也是固定的,实现下拉刷新还得用 SwipeRefreshLayout 来完成,这也容易理解,因为 BRVAH 主要是对 Adapter 的服务,所以这里只是简单说下 BRVAH 有关上拉加载更多的使用。

在按照 BRVAH 设置完 xxAdapter 后,在 Activity 中,让类实现 BaseQuickAdapter.RequestLoadMoreListener 接口,会重写 onLoadMoreRequested() 方法,在方法中调用 mAdapter.addData() 来添加新的数据,接着设置 mAdapter.loadMoreComplete(),在数据都加载完后设置 mAdapter.loadMoreEnd(false) 显示数据加载完毕。

@Overridepublic void onLoadMoreRequested() {mSwipeRefreshLayout.setEnabled(false);if (loadCount < 2) {final  List<MultipleItem> data = DataServer.getRefreshItemData(getServerData());mAdapter.addData(data);mAdapter.loadMoreComplete();loadCount+=1;} else {mAdapter.loadMoreEnd(false); // 显示加载完毕}// 设置下拉刷新实效mSwipeRefreshLayout.setEnabled(true);}

还有就是在下拉刷新的时候,使上拉加载更多失效。

mAdapter.setEnableLoadMore(true);

5. 实现Recyclerview 添加 Section 头部 View

设置 MySection 类继承 SectionEntity,创建不同的构造方法来设置 item 是否有 header。在 adapter 中,增加了 convertHead() 方法来加载 head 数据。在 Activity 中根据数据创建不同的 MySection 对象加入集合,设置给 adapter。

public class MySection  extends SectionEntity<String>{private boolean isMore;public MySection(boolean isHeader, String header,boolean isMore) {super(isHeader, header);this.isMore = isMore;}public MySection(String s) {super(s);}public void setMore(boolean more) {isMore = more;}
}

在 adapter 中,构造方法需要传入两个不同的布局 id,第一个是 item 的 layout id,第二个是 head,item 的数据加载在 convert() 方法中,head 的数据加载在 convertHead() 方法中。

public class SectionAdpater extends BaseSectionQuickAdapter<MySection,BaseViewHolder> {public SectionAdpater(int layoutResId, int sectionHeadResId, List<MySection> data) {super(layoutResId, sectionHeadResId, data);}// 加载 head 数据@Overrideprotected void convertHead(BaseViewHolder helper, MySection item) {helper.setText(R.id.title_tv,item.header);helper.addOnClickListener(R.id.more_btn);}// 加载 item 数据@Overrideprotected void convert(BaseViewHolder helper, MySection item) {}
}

在 Activity 中

...
// 部分代码
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);mRecyclerView.setLayoutManager(new GridLayoutManager(this,3));mData = getData(3);
SectionAdpater sectionAdpater = new SectionAdpater(R.layout.item_section_content,R.layout.def_section_head, mData);...// 假数据private List<MySection> getData(int size) {ArrayList<MySection> data = new ArrayList<>(size);data.add(new MySection(true,"1",true));for (int i =0;i < size;i++) {data.add(new MySection("haha"));}data.add(new MySection(true,"2",true));for (int i =0;i < size;i++) {data.add(new MySection("haha"));}data.add(new MySection(true,"3",true));for (int i =0;i < size;i++) {data.add(new MySection("haha"));}return data;}

根据数据确定不同的样式,用不同的构造方法设置 item 布局。

重要参考:BRVAH

搭配BRVAH高效使用RecyclerView相关推荐

  1. BRVAH(让RecyclerView变得更高效) (3)

    本文来自网易云社区 作者:吴思博 3 实现列表加载动画效果    3.1默认动画 我们只需将自建的 adapter 继承它对应满足需求的 Adapter,然后在 Activity 中实例化,通过ope ...

  2. 挑战练习10.6 实现高效的RecyclerView刷新

    把原本使用的Adapter的notifyDataSetChanged方法换成定位刷新RecyclerView.Adapter的notifyItem. 1.在CrimeListFragment里面定义一 ...

  3. [Android] DiffUtil在RecyclerView中的使用详解

    概述 DiffUtil是recyclerview support library v7 24.2.0版本中新增的类,根据Google官方文档的介绍,DiffUtil的作用是比较两个数据列表并能计算出一 ...

  4. (01)recyclerview的基本使用

    1.几个重要的类 1.1 简述:首先说明他的几个重要的类 1.1.2 RecyclerView.Adapter 抽象类,为RecyclerView提供数据,一般根据不同的业务需求来编写具体的实现类. ...

  5. 一个适用于ListView/GridView/RecyclerView的通用适配器

    简化大量重复代码 支持多布局 自定义图片加载 常用数据操作 view复用 RecyclerView item 点击和长按事件 GitHub源码地址 简书地址 gradle依赖 dependencies ...

  6. LinkedBlockingQueue源码解析(1)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.对于LinkedBlockingQueue需要掌握以下几点 创建 入队(添加元素) 出队(删除元素) 2 ...

  7. 网易有数的“正确”使用方式——洞察数据中隐藏的故事

    此文已由作者王文开授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 网易有数提供了用户非常灵活的图表制作能力,其设计原理是希望用户能够通过"搭积木"的形式, ...

  8. 知物由学 | 如何从勒索软件的攻击中全身而退

    欢迎访问网易云社区,了解更多网易技术产品运营经验. "知物由学"是网易云易盾打造的一个品牌栏目,词语出自汉·王充<论衡·实知>.人,能力有高下之分,学习才知道事物的道理 ...

  9. 微服务化的不同阶段 Kubernetes 的不同玩法

    欢迎访问网易云社区,了解更多网易技术产品运营经验. 作为容器集群管理技术竞争的大赢家,Kubernetes已经和微服务紧密联系,采用Kubernetes的企业往往都开始了微服务架构的探索.然而不同企业 ...

最新文章

  1. 【Flutter】Flutter 混合开发 ( 简介 | Flutter 混合开发集成步骤 | 创建 Flutter Module )
  2. 【Android 应用开发】Activity 返回堆栈清除操作 ( 默认状态 | 清除返回堆栈配置 | 不清除返回堆栈配置 | 清除指定界面配置 )
  3. 网络管理员&MCSE2003之12: 第8章 应用管理模板和审核策略
  4. 前端一HTML:二十四伪类
  5. rbac 权限分配, 基于formset实现,批量增加
  6. 真正的代码宝库:Google Code Search
  7. 学校为什么要单位接收函_为什么要选择语言学校留学?
  8. Windows XP图片查看器打不开图片的解决办法
  9. 基于web的客栈、公寓、民宿管理平台的设计与实现
  10. 作为管理者,就不要总等着领导给你布置任务了
  11. 云服务器部署论坛系统discuz,腾讯云服务器利用镜像搭建Discuz!论坛完整教程
  12. 多个约束的lagrange multiplier证明.
  13. OSChina 娱乐弹弹弹——程序猿的酒文化
  14. 2分钟部署人生模拟器,解锁人生新剧情
  15. QT之QTableWidget控件
  16. 网站是用什么来赚钱的?
  17. 2019年架构软考论文押题(二)
  18. 斐波那契生兔子问题(一月大兔子生a对,二月大兔子生b对,三月大兔子生c对。。。)
  19. Java会被禁吗_关于java:如果字符串对象被禁闭,那么为什么一个更改不会影响其他对象...
  20. 【PAT】06 图论

热门文章

  1. 机器学习中正则化技术
  2. licode源码分析-媒体数据的处理流程
  3. 阿里-应届生面试求职基础题以及答案(2)
  4. 小程序地图多点标记 marker
  5. 一个三流学校程序员的奋斗(勉)
  6. android sftp软件,Turbo FTP client SFTP client 安卓FTP、SFTP客户端推荐
  7. 30岁之前应该看的,三十而立!
  8. imageNet 的 top1-error和 top5-accuracy
  9. 趣味Python-初级凯撒加密
  10. 三国志战略版:Daniel_S2华夏吕深入分析