Android Filterable實(shí)現(xiàn)Recyclerview篩選功能的示例代碼
原先碰到篩選這種功能時(shí),后端的接口都會(huì)讓上傳一個(gè)字段,根據(jù)字段來(lái)返回相應(yīng)的數(shù)據(jù)。后來(lái)一次和別人對(duì)接時(shí),接口直接返回全部數(shù)據(jù),而且還要實(shí)現(xiàn)篩選功能。我...我說(shuō)不就是一條sql語(yǔ)句的事,改接口多方便,我苦心勸導(dǎo),然后被懟回來(lái),切,不就是篩選嘛,求人不如自己搞。
1. 效果圖

2. 思路
既然是篩選,那就少不了比較。也沒(méi)有什么好的辦法,無(wú)非就是循環(huán)對(duì)比,然后將適配器進(jìn)行數(shù)據(jù)更新。頁(yè)面刷新即可。但篩選的調(diào)用要方便,怎么比較才方便我們調(diào)用呢?偶然間看到了Filterable,使Adapter繼承自該接口,實(shí)現(xiàn)getFilter()方法,在該方法里實(shí)現(xiàn)具體的過(guò)濾邏輯即可。
3. 實(shí)現(xiàn)步驟
3.1 數(shù)據(jù)Bean類
class MyBean(var type:String,var name:String,var deliverType:String)
這里我們簡(jiǎn)單的創(chuàng)建個(gè)數(shù)據(jù)Bean類,后面我們的篩選字段是根據(jù)type和deliverType來(lái)進(jìn)行篩選。
3.2 創(chuàng)建適配器
class MyAdapter(data: MutableList<MyBean>) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>(), Filterable {
//存放原數(shù)據(jù)
private var mSourceList = mutableListOf<MyBean>()
//存放過(guò)濾后的數(shù)據(jù)
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)
}
/**
* 注意:這里返回過(guò)濾后的集合大小
*/
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)
}
}
和我們平時(shí)創(chuàng)建的Adapter沒(méi)什么兩樣。但要注意以下幾點(diǎn)
1、這里我們創(chuàng)建了兩個(gè)集合mSourceList和mFilterList,mFilterList主要是用來(lái)存放過(guò)濾后的數(shù)據(jù),而mSourceList主要是用來(lái)在篩選后數(shù)據(jù)恢復(fù)時(shí)使用,使得不用再去請(qǐng)求一次數(shù)據(jù)。
2、getItemCount()方法返回過(guò)濾后的集合的大小。
有個(gè)疑問(wèn):
假如我們沒(méi)有進(jìn)行過(guò)濾,而因?yàn)槲覀兊膍FilterList默認(rèn)為空,且getItemCount()返回的是它的大小0,那我們默認(rèn)是不是就顯示不出數(shù)據(jù)?
3.3 繼承Filterable接口
1、繼承Filterable接口后,實(shí)現(xiàn)其getFilter()方法,該方法需要我們返回一個(gè)Filter過(guò)濾器對(duì)象。
2、我們重寫Filter的performFiltering()方法和publishResults()方法,performFiltering()用來(lái)實(shí)現(xiàn)我們具體過(guò)濾的邏輯操作,publishResults()用來(lái)將我們過(guò)濾后的數(shù)據(jù)進(jìn)行更新。
3、因?yàn)閜erformFiltering()傳來(lái)的過(guò)濾條件是一段字符串,而我們的過(guò)濾條件有兩個(gè),所以我們將過(guò)濾的條件轉(zhuǎn)化為Json對(duì)象傳過(guò)來(lái),那樣就可以得到多個(gè)過(guò)濾條件的字符串了。
4、這里我們的具體過(guò)濾操作是使用Collection的filter()方法進(jìn)行過(guò)濾
(1)當(dāng)condition1和condition2為空時(shí),返回原數(shù)據(jù)mSourceList
(2)否則使用filter()方法按條件進(jìn)行過(guò)濾,最后將過(guò)濾后的集合賦值給FilterResults()對(duì)象的value字段,并將其返回
5、publishResults(charSequence: CharSequence,filterResults: FilterResults)方法中filterResults對(duì)象內(nèi)的value字段是我們performFiltering()方法返回的過(guò)濾后的集合,在這里我們將RecyclerView進(jìn)行更新。
具體實(shí)現(xiàn)見(jiàn)以下代碼:
class MyAdapter(data: MutableList<MyBean>) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>(), Filterable {
/**
* 具體的執(zhí)行過(guò)濾的操作
* 創(chuàng)建適配器后會(huì)默認(rèn)的執(zhí)行一次
*/
override fun getFilter(): Filter {
return object : Filter() {
//執(zhí)行過(guò)濾操作
override fun performFiltering(charSequence: CharSequence): FilterResults {
val charString = charSequence.toString()
Log.i(TAG, "performFiltering: 執(zhí)行過(guò)濾操作,過(guò)濾字段為:$charString")
val jsonObject = JSONObject(charString)
//篩選條件一
var condition1 = jsonObject.getString("condition1")
//篩選條件二
var condition2 = jsonObject.getString("condition2")
//存放已過(guò)濾的數(shù)據(jù)
var theFilterList = if (condition1.isEmpty() && condition2.isEmpty()) {
//沒(méi)有過(guò)濾的內(nèi)容,則使用源數(shù)據(jù)
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
}
//把過(guò)濾后的值返回出來(lái)并進(jìn)行更新
override fun publishResults(
charSequence: CharSequence,
filterResults: FilterResults
) {
mFilterList = filterResults.values as MutableList<MyBean>
notifyDataSetChanged()
}
}
}
}
3.4 過(guò)濾調(diào)用
class MainActivity : AppCompatActivity() {
//過(guò)濾條件1
var condition1 = ""
//過(guò)濾條件2
var condition2 = ""
//總的過(guò)濾條件
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","過(guò)濾條件一")
jsonObject.put("condition2","過(guò)濾條件二")
myAdapter.filter.filter(jsonObject.toString())
}
}
如果想恢復(fù)數(shù)據(jù)不篩選,直接將jsonObject對(duì)象內(nèi)的condition1和condition2字段設(shè)為空,然后調(diào)用myAdapter.filter.filter(jsonObject.toString())即可。
具體見(jiàn)代碼
4. 優(yōu)化
其實(shí)我們getFilter()內(nèi)的過(guò)濾操作還可以優(yōu)化下
var theFilterList = if (condition1.isEmpty() && condition2.isEmpty()) {
//沒(méi)有過(guò)濾的內(nèi)容,則使用源數(shù)據(jù)
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{}下是當(dāng)condition1和condition2都不為空的情況下進(jìn)行的篩選,但是如果我們使用下拉框進(jìn)行篩選時(shí),選擇第一個(gè)條件condition1后就已經(jīng)進(jìn)行了一次篩選,即condition1不為空condition2為空,在 else if (condition2.isEmpty()){} 里對(duì)源數(shù)據(jù)進(jìn)行了篩選;再選擇第二個(gè)條件時(shí),又進(jìn)行了一次篩選,即condition1不為空condition2不為空,在else{}里又是對(duì)源數(shù)據(jù)進(jìn)行篩選,其實(shí)我們應(yīng)該是在第一次的結(jié)果下進(jìn)行篩選是最優(yōu)的辦法。
想法很好,但實(shí)現(xiàn)起來(lái)困難挺多,在兩個(gè)條件都不為空時(shí),我們需要判斷第一次刪選下來(lái)的數(shù)據(jù)是以哪個(gè)篩選條件為依據(jù)的,在兩個(gè)條件都不為空篩選后,再次更改其中一個(gè)篩選條件,我們需要先將另外一個(gè)篩選條件下的數(shù)據(jù)給篩選出來(lái),越來(lái)越麻煩,暫時(shí)不考慮了,有好的方案的麻煩給個(gè)思路。
5. 注意
因?yàn)锳dapter默認(rèn)返回的大小是篩選后的尺寸,而我們默認(rèn)是沒(méi)有篩選的,導(dǎo)致上來(lái)會(huì)沒(méi)有數(shù)據(jù),所以我們需要設(shè)置適配器后,人為的調(diào)用一下篩選才好:myAdapter.filter.filter(jsonObject.toString())。而我在項(xiàng)目中沒(méi)有寫因?yàn)锳ppCompatSpinner會(huì)默認(rèn)的選擇第0項(xiàng),我在其onItemSelected()回調(diào)里調(diào)用了篩選功能。
6. 總結(jié)
總的來(lái)說(shuō)并不難,還是更新數(shù)據(jù)更新布局的那一套,不同的是用了Filterable接口實(shí)現(xiàn),使得篩選調(diào)用的方式更簡(jiǎn)單。但是這種實(shí)現(xiàn)更多的是適用于數(shù)據(jù)量小或者固定的數(shù)據(jù),如果數(shù)據(jù)量大,或者數(shù)據(jù)會(huì)一直上拉加載擴(kuò)充,使用這種方式只會(huì)讓效率隨著數(shù)據(jù)量的增大而越來(lái)越低,顯然不合適,下次后端還強(qiáng)硬不改,那就只能開(kāi)懟了。
Github項(xiàng)目地址 https://github.com/myfittinglife/RecyclerViewFilterable
7. 參考文章
到此這篇關(guān)于Android Filterable實(shí)現(xiàn)Recyclerview篩選功能的示例代碼的文章就介紹到這了,更多相關(guān)Android Recyclerview篩選內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android WebView如何判定網(wǎng)頁(yè)加載的錯(cuò)誤
- Android實(shí)現(xiàn)View滑動(dòng)效果的6種方法
- Android控件View的文字周圍添加圖標(biāo)
- 自己實(shí)現(xiàn)Android View布局流程
- 如何自己實(shí)現(xiàn)Android View Touch事件分發(fā)流程
- Android webView字體突然變小的原因及解決
- Android 滑動(dòng)Scrollview標(biāo)題欄漸變效果(仿京東toolbar)
- Android自定義View用切圖顯示字符串
- Android View 事件防抖的兩種方案
相關(guān)文章
Android編程實(shí)現(xiàn)網(wǎng)絡(luò)圖片查看器和網(wǎng)頁(yè)源碼查看器實(shí)例
這篇文章主要介紹了Android編程實(shí)現(xiàn)網(wǎng)絡(luò)圖片查看器和網(wǎng)頁(yè)源碼查看器,結(jié)合實(shí)例形式分析了Android針對(duì)網(wǎng)絡(luò)圖片及網(wǎng)頁(yè)的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-01-01
Android開(kāi)發(fā)之TextView控件用法實(shí)例總結(jié)
這篇文章主要介紹了Android開(kāi)發(fā)之TextView控件用法,結(jié)合實(shí)例形式總結(jié)分析了TextView控件常用的屬性設(shè)置及使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-02-02
Android計(jì)步模塊實(shí)例代碼(類似微信運(yùn)動(dòng))
本篇文章主要介紹了Android計(jì)步模塊實(shí)例代碼(類似微信運(yùn)動(dòng)),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Android自定義短信倒計(jì)時(shí)view流程分析
倒計(jì)時(shí)實(shí)現(xiàn)有三種方式 而這個(gè)自定義view是通過(guò)handler實(shí)現(xiàn)的。本文通過(guò)實(shí)例代碼給大家介紹Android自定義短信倒計(jì)時(shí)view流程,,需要的朋友可以參考下2020-03-03
Android 動(dòng)態(tài)加載二維碼視圖生成快照的示例
本篇文章主要介紹了Android 動(dòng)態(tài)加載二維碼視圖生成快照的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
Android時(shí)分秒計(jì)時(shí)器的兩種實(shí)現(xiàn)方法
這篇文章主要介紹了Android時(shí)分秒計(jì)時(shí)器的兩種實(shí)現(xiàn)方法,分別是Chronometer控件和handler+timer+timerTask方式,非常不錯(cuò),感興趣的朋友一起看下吧2016-08-08

