Android Filterable实现Recyclerview筛选功能的示例代码
作者:重拾丢却的梦 发布时间:2023-08-30 16:52:47
目录
1. 效果图
2. 思路
3. 实现步骤
3.1 数据Bean类
3.2 创建适配器
3.3 继承Filterable接口
3.4 过滤调用
4. 优化
5. 注意
6. 总结
7. 参考文章
原先碰到筛选这种功能时,后端的接口都会让上传一个字段,根据字段来返回相应的数据。后来一次和别人对接时,接口直接返回全部数据,而且还要实现筛选功能。我...我说不就是一条sql语句的事,改接口多方便,我苦心劝导,然后被怼回来,切,不就是筛选嘛,求人不如自己搞。
1. 效果图
2. 思路
既然是筛选,那就少不了比较。也没有什么好的办法,无非就是循环对比,然后将适配器进行数据更新。页面刷新即可。但筛选的调用要方便,怎么比较才方便我们调用呢?偶然间看到了Filterable,使Adapter继承自该接口,实现getFilter()方法,在该方法里实现具体的过滤逻辑即可。
3. 实现步骤
3.1 数据Bean类
class MyBean(var type:String,var name:String,var deliverType:String)
这里我们简单的创建个数据Bean类,后面我们的筛选字段是根据type和deliverType来进行筛选。
3.2 创建适配器
class MyAdapter(data: MutableList<MyBean>) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>(), Filterable {
//存放原数据
private var mSourceList = mutableListOf<MyBean>()
//存放过滤后的数据
private var mFilterList = mutableListOf<MyBean>()
init {
mSourceList = data
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.name.text = mFilterList[position].name
holder.deliverType.text = mFilterList[position].deliverType
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
var view =
LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
return MyViewHolder(view)
}
/**
* 注意:这里返回过滤后的集合大小
*/
override fun getItemCount(): Int {
return mFilterList.size
}
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
//商品名称
var name: TextView = itemView.findViewById(R.id.tvName)
//配送方式
var deliverType: TextView = itemView.findViewById(R.id.tvDeliverType)
}
}
和我们平时创建的Adapter没什么两样。但要注意以下几点
1、这里我们创建了两个集合mSourceList和mFilterList,mFilterList主要是用来存放过滤后的数据,而mSourceList主要是用来在筛选后数据恢复时使用,使得不用再去请求一次数据。
2、getItemCount()方法返回过滤后的集合的大小。
有个疑问:
假如我们没有进行过滤,而因为我们的mFilterList默认为空,且getItemCount()返回的是它的大小0,那我们默认是不是就显示不出数据?
3.3 继承Filterable接口
1、继承Filterable接口后,实现其getFilter()方法,该方法需要我们返回一个Filter过滤器对象。
2、我们重写Filter的performFiltering()方法和publishResults()方法,performFiltering()用来实现我们具体过滤的逻辑操作,publishResults()用来将我们过滤后的数据进行更新。
3、因为performFiltering()传来的过滤条件是一段字符串,而我们的过滤条件有两个,所以我们将过滤的条件转化为Json对象传过来,那样就可以得到多个过滤条件的字符串了。
4、这里我们的具体过滤操作是使用Collection的filter()方法进行过滤
(1)当condition1和condition2为空时,返回原数据mSourceList
(2)否则使用filter()方法按条件进行过滤,最后将过滤后的集合赋值给FilterResults()对象的value字段,并将其返回
5、publishResults(charSequence: CharSequence,filterResults: FilterResults)方法中filterResults对象内的value字段是我们performFiltering()方法返回的过滤后的集合,在这里我们将RecyclerView进行更新。
具体实现见以下代码:
class MyAdapter(data: MutableList<MyBean>) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>(), Filterable {
/**
* 具体的执行过滤的操作
* 创建适配器后会默认的执行一次
*/
override fun getFilter(): Filter {
return object : Filter() {
//执行过滤操作
override fun performFiltering(charSequence: CharSequence): FilterResults {
val charString = charSequence.toString()
Log.i(TAG, "performFiltering: 执行过滤操作,过滤字段为:$charString")
val jsonObject = JSONObject(charString)
//筛选条件一
var condition1 = jsonObject.getString("condition1")
//筛选条件二
var condition2 = jsonObject.getString("condition2")
//存放已过滤的数据
var theFilterList = if (condition1.isEmpty() && condition2.isEmpty()) {
//没有过滤的内容,则使用源数据
mSourceList
} else if (condition2.isEmpty()) {
mSourceList.filter { it.type == condition1 }
} else if (condition1.isEmpty()) {
mSourceList.filter { it.deliverType == condition2 }
} else {
mSourceList.filter { it.type == condition1 && it.deliverType == condition2 }
}
val filterResults = FilterResults()
filterResults.values = theFilterList
return filterResults
}
//把过滤后的值返回出来并进行更新
override fun publishResults(
charSequence: CharSequence,
filterResults: FilterResults
) {
mFilterList = filterResults.values as MutableList<MyBean>
notifyDataSetChanged()
}
}
}
}
3.4 过滤调用
class MainActivity : AppCompatActivity() {
//过滤条件1
var condition1 = ""
//过滤条件2
var condition2 = ""
//总的过滤条件
var jsonObject = JSONObject()
private var dataList = mutableListOf<MyBean>()
var myAdapter = MyAdapter(dataList)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mRecyclerView.layoutManager = LinearLayoutManager(this)
mRecyclerView.adapter = myAdapter
jsonObject.put("condition1","过滤条件一")
jsonObject.put("condition2","过滤条件二")
myAdapter.filter.filter(jsonObject.toString())
}
}
如果想恢复数据不筛选,直接将jsonObject对象内的condition1和condition2字段设为空,然后调用myAdapter.filter.filter(jsonObject.toString())即可。
具体见代码
4. 优化
其实我们getFilter()内的过滤操作还可以优化下
var theFilterList = if (condition1.isEmpty() && condition2.isEmpty()) {
//没有过滤的内容,则使用源数据
mSourceList
} else if (condition2.isEmpty()) {
mSourceList.filter { it.type == condition1 }
} else if (condition1.isEmpty()) {
mSourceList.filter { it.deliverType == condition2 }
} else {
mSourceList.filter { it.type == condition1 && it.deliverType == condition2 }
}
可以看到else{}下是当condition1和condition2都不为空的情况下进行的筛选,但是如果我们使用下拉框进行筛选时,选择第一个条件condition1后就已经进行了一次筛选,即condition1不为空condition2为空,在 else if (condition2.isEmpty()){} 里对源数据进行了筛选;再选择第二个条件时,又进行了一次筛选,即condition1不为空condition2不为空,在else{}里又是对源数据进行筛选,其实我们应该是在第一次的结果下进行筛选是最优的办法。
想法很好,但实现起来困难挺多,在两个条件都不为空时,我们需要判断第一次删选下来的数据是以哪个筛选条件为依据的,在两个条件都不为空筛选后,再次更改其中一个筛选条件,我们需要先将另外一个筛选条件下的数据给筛选出来,越来越麻烦,暂时不考虑了,有好的方案的麻烦给个思路。
5. 注意
因为Adapter默认返回的大小是筛选后的尺寸,而我们默认是没有筛选的,导致上来会没有数据,所以我们需要设置适配器后,人为的调用一下筛选才好:myAdapter.filter.filter(jsonObject.toString())。而我在项目中没有写因为AppCompatSpinner会默认的选择第0项,我在其onItemSelected()回调里调用了筛选功能。
6. 总结
总的来说并不难,还是更新数据更新布局的那一套,不同的是用了Filterable接口实现,使得筛选调用的方式更简单。但是这种实现更多的是适用于数据量小或者固定的数据,如果数据量大,或者数据会一直上拉加载扩充,使用这种方式只会让效率随着数据量的增大而越来越低,显然不合适,下次后端还强硬不改,那就只能开怼了。
Github项目地址 https://github.com/myfittinglife/RecyclerViewFilterable
7. 参考文章
集合过滤操作
Google文档
来源:https://juejin.cn/post/6924132314192543757


猜你喜欢
- 一、前言在日常工作中,如果涉及到与第三方进行接口对接,有的会使用WebService的方式,这篇文章主要讲解在.NET Framework中
- final——final用于类表示该类不能派生子类。final用于方法表示该方法不能被子类重写。final用于变量时表示常量,类似于C/C+
- 首先,我们需要增加用户对该脚本的执行权限,即 String cmdstring = "chmod a+x test.sh
- 本文实例讲述了C#实现为一张大尺寸图片创建缩略图的方法。分享给大家供大家参考。具体实现方法如下:public static Bitmap C
- 一、分布式锁使用场景:代码部署在多台服务器上,即分布式部署。多个进程同步访问一个共享资源。二、需要的技术:数据库:mongojava:mon
- 前言Java中容器对象主要用来存储其他对象,根据实现原理不同,主要有3类常用的容器对象:1、ArrayList 使用数组结构存储容器中的元素
- 本项目使用的环境:开发工具:Intellij IDEA 2017.1.3springboot: 1.5.6jdk:1.8.0_161mave
- 本文实例为大家分享了java实现KFC点餐系统的具体代码,供大家参考,具体内容如下package KFC点餐系统;//food 类 publ
- 我们知道,多线程是Android开发中必现的场景,很多原生API和开源项目都有多线程的内容,这里简单总结和探讨一下常见的多线程切换方式。我们
- 系统有很多光标类型 :Cursors 类 (System.Windows.Input) | Microsoft Docs本章介绍如何自定义光
- 在安卓操作系统下对于 TextView 字体的支持非常有限,默认情况下 TextView 的 typeface 属性支持 "San
- 使用过 mybatis 框架的小伙伴们都知道,mybatis 是个半 orm 框架,通过写 mapper 接口就能自动实现数据库的增删改查,
- 这段时间花了点时间整理了几个新手易犯的典型缺陷(专门针对C#的),但是个人的力量毕竟有限缺陷的覆盖面比较窄,有些缺陷的描述也不够准确,这里先
- 本文章主要讲二维数组定义,用法。1.什么是二维数组在二维数组多个元素为一维数组的数组就称为二维数组2.定义格式格式一:元素的数据类型[][]
- 在使用各类App的时候,尤其是在发布朋友圈、微博的时候,都会选择配图,进入手机相册,选择自己想要的照片,作为发布内容的一部分,这里就简单介绍
- 1)new 运算符:用于创建对象和调用构造函数。这种大家都比较熟悉,没什么好说的了。2)new 修饰符:在用作修饰符时,new 关键字可以显
- 几种序列化技术:1)二进制序列化保持类型保真度,这对于在应用程序的不同调用之间保留对象的状态很有用。例如,通过将对象序列化到剪贴板,可在不同
- 本文实例讲述了Java网络编程实现的简单端口扫描器。分享给大家供大家参考,具体如下:在计算机网络的学习中,不由得觉得这门课的零碎知识点异常之
- 目录问题产生如何解决总结问题产生默认生成的flutter工程,在启动时候会白屏,设备性能越差,白屏时间越长。原生Android开发也会遇到类
- 今天写这篇文章的缘由是前一段时间一个网友在我的博客上面留言,想要实现在GridLayout(相当于九宫格)中点击每项可左右滑动显