基于RecyclerView实现的分组显示信息demo
概述
详细
一、效果
先上效果图给大家看看,好有一个整体的认识,(
我的github地址:
https://github.com/nbwzlyd/SectionRecyclerViewDemo
)
当然如果你觉得帮助到你的话,可以以资鼓励哦
二、实现过程
效果就是这样的,但是不仅仅局限于这种布局,事实上只要是三段式布局,都可以通过该demo的学习来实现,什么是三段式布局呢,就是有header -content-footer类型的布局,画一个图来解释
比如下面这个图就可以
可以看到,用途还是很广泛的,所以很需要我们去学习一下
怎么去实现
gitbub上有一个很牛逼的类,但是貌似知道的人很少,名字叫做SectionedRecyclerViewAdapter ,地址https://github.com/truizlop/SectionedRecyclerView 但是今天我们不去研究她是怎么实现的,我们来研究他怎么用就行了
继承SectionedRecyclerViewAdapter
/**
* Created by lyd10892 on 2016/8/23.
*/
public class HotelEntityAdapter extends SectionedRecyclerViewAdapter<HeaderHolder, DescHolder, RecyclerView.ViewHolder> {
public ArrayList<HotelEntity.TagsEntity> allTagList;
private Context mContext;
private LayoutInflater mInflater;
private SparseBooleanArray mBooleanMap;//记录下哪个section是被打开的
public HotelEntityAdapter(Context context) {
mContext = context;
mInflater = LayoutInflater.from(context);
mBooleanMap = new SparseBooleanArray();
}
public void setData(ArrayList<HotelEntity.TagsEntity> allTagList) {
this.allTagList = allTagList;
notifyDataSetChanged();
}
@Override
protected int getSectionCount() {
return HotelUtils.isEmpty(allTagList) ? 0 : allTagList.size();
}
@Override
protected int getItemCountForSection(int section) {
int count = allTagList.get(section).tagInfoList.size();
if (count >= 8 && !mBooleanMap.get(section)) {
count = 8;
}
return HotelUtils.isEmpty(allTagList.get(section).tagInfoList) ? 0 : count;
}
//是否有footer布局
@Override
protected boolean hasFooterInSection(int section) {
return false;
}
@Override
protected HeaderHolder onCreateSectionHeaderViewHolder(ViewGroup parent, int viewType) {
return new HeaderHolder(mInflater.inflate(R.layout.hotel_title_item, parent, false));
}
@Override
protected RecyclerView.ViewHolder onCreateSectionFooterViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
protected DescHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
return new DescHolder(mInflater.inflate(R.layout.hotel_desc_item, parent, false));
}
@Override
protected void onBindSectionHeaderViewHolder(final HeaderHolder holder, final int section) {
holder.openView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean isOpen = mBooleanMap.get(section);
String text = isOpen ? "展开" : "关闭";
mBooleanMap.put(section, !isOpen);
holder.openView.setText(text);
notifyDataSetChanged();
}
});
holder.titleView.setText(allTagList.get(section).tagsName);
holder.openView.setText(mBooleanMap.get(section) ? "关闭" : "展开");
}
@Override
protected void onBindSectionFooterViewHolder(RecyclerView.ViewHolder holder, int section) {
}
@Override
protected void onBindItemViewHolder(DescHolder holder, int section, int position) {
holder.descView.setText(allTagList.get(section).tagInfoList.get(position).tagName);
}
}
这里面有几个很重要的方法也是需要我们必须重写的,是我们实现效果的关键
protected abstract int getSectionCount();
protected abstract int getItemCountForSection(int section);
protected abstract boolean hasFooterInSection(int section);
protected abstract H onCreateSectionHeaderViewHolder(ViewGroup parent, int viewType);
protected abstract F onCreateSectionFooterViewHolder(ViewGroup parent, int viewType);
protected abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType);
protected abstract void onBindSectionHeaderViewHolder(H holder, int section);
protected abstract void onBindSectionFooterViewHolder(F holder, int section);
protected abstract void onBindItemViewHolder(VH holder, int section, int position);
接下来我们详细分析这几个方法存在的具体意义
不过在说之前我们需要看一下我们的数据结构,这个也很重要
public class HotelEntity {
/**
* 要注意这个类的数据结构,很重要,直接决定了我们能不能实现分组展示
*/
public ArrayList<TagsEntity> allTagsList;
public class TagsEntity {
public String tagsName;
public ArrayList<TagInfo> tagInfoList;
public class TagInfo {
public String tagName;
}
}
}
这个方法主要是用来计算我们一共有多少个section需要展示,返回值是我们最外称list的大小,在我们的示例图中,对应的为热门品牌—商业区—热门景点 等,对应的数据是我们的allTagList
protected abstract int getSectionCount();
这个方法是用来展示content内容区域,返回值是我们需要展示多少内容,在本例中,我们超过8条数据只展示8条,点击展开后就会展示全部数据,逻辑就在这里控制。 对应数据结构为tagInfoList
protected abstract int getItemCountForSection(int section);
判断是否需要底部footer布局,在该例中,我们并不需要显示footer,所以默认返回false就可以,如果你对应的section需要展示footer布局,那么就在对应的section返回true就行了
protected abstract boolean hasFooterInSection(int section);
我们要单独说一下这个方法,这里有一个section和position ,有些人可能会弄混
section是区域,也就是我们最外层的index,position是每个section对应的内容数据的position
@Override
protected void onBindItemViewHolder(DescHolder holder, int section, int position) {
holder.descView.setText(allTagList.get(section).tagInfoList.get(position).tagName);
}
至于下面的onCreateViewHolder ,onBindViewHolder不多做解释了,如果你用过recyclerView,使用方法是一样的,无非是渲染布局,绑定数据
展示数据
基本上,如果上面的adapter逻辑写完,我们的布局算是完成了,首页代码如下
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private HotelEntityAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mAdapter = new HotelEntityAdapter(this);
GridLayoutManager manager = new GridLayoutManager(this,4);//我们需要网格式的布局
//设置header占据的空间
manager.setSpanSizeLookup(new SectionedSpanSizeLookup(mAdapter,manager));
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(mAdapter);
HotelEntity entity = JsonUtils.analysisJsonFile(this,"json");
mAdapter.setData(entity.allTagsList);
}
}
代码里有一段很重要的注释,设置header占据的空间,没错,因为我们要仿造header的效果,我们设置的manager是GridLayoutManager,设置的每一行item数量是4,如果不重写该方法,那么header显示就会出错,核心代码如下:
/**
* A SpanSizeLookup to draw section headers or footer spanning the whole width of the RecyclerView
* when using a GridLayoutManager
*
* 这个类是用来自定义每个item需要占据的空间
*
*
*/
public class SectionedSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
protected SectionedRecyclerViewAdapter<?, ?, ?> adapter = null;
protected GridLayoutManager layoutManager = null;
public SectionedSpanSizeLookup(SectionedRecyclerViewAdapter<?, ?, ?> adapter, GridLayoutManager layoutManager) {
this.adapter = adapter;
this.layoutManager = layoutManager;
}
@Override
public int getSpanSize(int position) {
//header和footer占据的是全屏
if(adapter.isSectionHeaderPosition(position) || adapter.isSectionFooterPosition(position)){
return layoutManager.getSpanCount();
}else{
return 1;//其他默认1
}
}
}
最重要的是getSpanSize方法,只要是header或者是footer就返回我们设置的网格数,也就是4,代表header和footer占据4个网格的空间,其他占据1个
这样,我们就可以完美的展示我们需要的布局了
当前我们的demo是网格布局的,你也可以设置流式布局,只需要设置不同的layoutmanager就可以了
比如下图的效果我们也可以实现
核心代码已经解释完毕,当然最核心的是SectionedRecyclerViewAdapter这个类,这个类好好学习一下,会学到很多,也会实现很多app常见的布局效果,比如设置不同的viewType展现更复杂的布局
三、项目结构
最后,看一下代码结构:
四、其他补充
最后啰嗦一句,写博客比写代码难多了。
我的github地址:
https://github.com/nbwzlyd/SectionRecyclerViewDemo
记得给星星哦。
注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权
基于RecyclerView实现的分组显示信息demo的更多相关文章
- wpf CollectionViewSource与ListBox的折叠、分组显示,及输入关键字 Filter的筛选
在wpf中虽然ObservableCollection<T>作为ListBox的Itemsource,很好,很强大!但是CollectionViewSource与ListBox才是天作之合 ...
- 关于MySQL相关的查看显示信息:
关于MySQL相关的查看显示信息: 数据库范围: 一.查看所有的数据库:(仅仅是看数据库数量与名字) mysql> show databases; 二.查看某个数据库的创建信息:(主要看数据库的 ...
- Group GridView:用于.Net的分组显示的GridView
我的项目需要一个可以分组显示的GridView,我不会写,上网找了一圈,最终在国外的网站上找到的这个,比较符合我的要求,但它的分页得重写,它写了能分页,但我发现它的分页功能事实上并没有实现,也不知道是 ...
- 转:基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴等)【模式识别中的翘楚】
文章来自于:http://blog.renren.com/share/246648717/8171467499 基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴 ...
- Asp.Net Core基于JWT认证的数据接口网关Demo
近日,应一位朋友的邀请写了个Asp.Net Core基于JWT认证的数据接口网关Demo.朋友自己开了个公司,接到的一个升级项目,客户要求用Aps.Net Core做数据网关服务且基于JWT认证实现对 ...
- 广深小龙-基于unittest、pytest自动化测试框架之demo来学习啦!!!
基于unittest.pytest自动化测试框架之demo,赶紧用起来,一起学习吧! demo分为两个框架:①pytest ②unittest demo 中 包含 web.api 自动化测试框架 ...
- 11月10日下午 ajax做显示信息以后用ajax、Bootstrp做弹窗显示信息详情
1.用ajax做弹窗显示信息详情 nation.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&qu ...
- Linq DataTable Group By 分组显示人员明细
实现功能: 多个字段分组源码样例: 原始数据: 分组后的输出结果: 源代码: public static void PrintPersons() { //准备数据 DataTable dt ...
- 重新想象 Windows 8 Store Apps (12) - 控件之 GridView 特性: 拖动项, 项尺寸可变, 分组显示
原文:重新想象 Windows 8 Store Apps (12) - 控件之 GridView 特性: 拖动项, 项尺寸可变, 分组显示 [源码下载] 重新想象 Windows 8 Store Ap ...
随机推荐
- 【没有注意过的细节】用scanf读一个unsigned char? %hhu 的用法
头段时间我的代码,有一个 unsigned char,我需要从sscanf 中读取字符串为这个值.但是一般char 是用%c的,我是要值得. 所以我使用了%d %u来读,结果报警告: unsigned ...
- Qt实现自定义按钮的三态效果
好久之前做的一个小软件,好长时间没动过了,在不记录下有些细节可能都忘了,这里整理下部分功能的实现. 按钮的三态,指的是普通态.鼠标的停留态.点击态,三态是界面交互非常基本的一项功能,Qt中如果使用的是 ...
- Asp.Net MVC3 简单教程(三)详解Controller之Filter 【转】
前言 前面两篇写的比较简单,刚开始写这个系列的时候我面向的对象是刚开始接触Asp.Net MVC的朋友,所以写的尽量简单.所以写的没多少技术含量.把这些技术总结出来,然后一简单的方式让更多的人很好的接 ...
- 【转】从QDataStream向QByteArray中写入数据时的注意点(QT)
最近发现从QDataStream向QByteArray中写入数据常常是写不进去的,通过查看QT的源码: QDataStream &operator>>(QDataStream &a ...
- 命令行调用dubbo远程服务
命令行调用dubbo远程服务 telnet远程连接到dubbo telnet 127.0.0.1 20880 查看提供服务的接口 dubbo>ls com.test.service.TestIn ...
- go语言之进阶篇json解析到map
1.json解析到map(通过类型断言,找到值和value类型) 示例: package main import ( "encoding/json" "fmt" ...
- 算法-强连通分量和Kosaraju算法
有向图中,连通性比较好理解,如果两个顶点V和顶点W是可达的,可以称之为强连通的,即存在路径A→B,同时也存在一条有向路径B→A.从之前的有向环的判定过程中其实我们可以得到一个结论就是两个是强连通的当且 ...
- vue里ref ($refs)用法
ref 有三种用法: 1.ref 加在普通的元素上,用this.ref.name 获取到的是dom元素 2.ref 加在子组件上,用this.ref.name 获取到的是组件实例,可以使用组件的所有方 ...
- 详解vue组件的keep-alive
<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM. <keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是 ...
- centos下配置sftp且限制用户访问目录
SFTP在Linux下是一个很方便很安全的文件传输工具,我常常用它在Linux服务器上替代传统的ftp来传输文件.众所周知SFTP账号是基于SSH账号的,默认情况下访问服务器的权限很大,下面的教程就是 ...