فیلتر جستجو روی Recycler View در اندروید — راهنمای کاربردی
اگر به طور مکرر نیازمند پیادهسازی قابلیت جستجو برای لیستها در اپلیکیشنهای اندرویدی هستید، این مقاله برای شما کاملاً مفید خواهد بود. در این راهنما روشی عالی برای پیادهسازی یک آداپتر دینامیک مجرد معرفی میکنیم که میتواند برای استفاده از فیلتر جستجو روی Recycler View به کار گرفته شود.
شروع
ابتدا باید یک آداپتر Recycler View بسازید تا لیستبندیها را مدیریت کنید. با این حال به جای نوع استاندارد، DynamicSearchAdapter (+) را بسط میدهیم.
زمانی که این کار را انجام دادید، لیست خود را در اختیار آداپتر والد قرار دهید و ضمناً لیست را داخل <> به عنوان پارامتر نوع قرار دهید. اینک میتوانید از قابلیت جستجو در هر تعداد از لیستها در اکتیویتیها یا فرگمانها استفاده کنید.
برای نمونه یک پیادهسازی ساده برای 2 مورد از آداپترهای متفاوت میتواند مانند زیر باشد:
1class SearchAdapter1(private val mutableList: MutableList<SearchModel1>) :
2 DynamicSearchAdapter<SearchModel1>(mutableList) {
3
4
5 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
6 val textView = TextView(parent.context)
7 return ViewHolder(textView)
8 }
9
10 override fun getItemCount(): Int {
11 return mutableList.count()
12 }
13
14 override fun onBindViewHolder(holder: ViewHolder, position: Int) {
15 val tv = holder.containerView as TextView
16 tv.text = mutableList[position].data
17
18 }
19
20
21}
22class SearchAdapter2(private val mutableList: MutableList<SearchModel2>) :
23 DynamicSearchAdapter<SearchModel2>(mutableList) {
24
25 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
26 val textView = TextView(parent.context)
27 return ViewHolder(textView)
28 }
29
30 override fun getItemCount(): Int {
31 return mutableList.count()
32 }
33
34 override fun onBindViewHolder(holder: ViewHolder, position: Int) {
35 val tv = holder.containerView as TextView
36 tv.text = mutableList[position].data
37
38 }
39
40
41}
کد آداپتر جستجوی دینامیک مجرد به صورت زیر است:
1abstract class DynamicSearchAdapter<T : DynamicSearchAdapter.Searchable>(private val searchableList: MutableList<T>) :
2 RecyclerView.Adapter<ViewHolder>(), Filterable {
3
4 // Single not-to-be-modified copy of original data in the list.
5 private val originalList = ArrayList(searchableList)
6 // a method-body to invoke when search returns nothing. It can be null.
7 private var onNothingFound: (() -> Unit)? = null
8
9 /**
10 * Searches a specific item in the list and updates adapter.
11 * if the search returns empty then onNothingFound callback is invoked if provided which can be used to update UI
12 * @param s the search query or text. It can be null.
13 * @param onNothingFound a method-body to invoke when search returns nothing. It can be null.
14 */
15 fun search(s: String?, onNothingFound: (() -> Unit)?) {
16 this.onNothingFound = onNothingFound
17 filter.filter(s)
18
19 }
20
21 override fun getFilter(): Filter {
22 return object : Filter() {
23 private val filterResults = FilterResults()
24 override fun performFiltering(constraint: CharSequence?): FilterResults {
25 searchableList.clear()
26 if (constraint.isNullOrBlank()) {
27 searchableList.addAll(originalList)
28 } else {
29 val searchResults = originalList.filter { it.getSearchCriteria().contains(constraint) }
30 searchableList.addAll(searchResults)
31 }
32 return filterResults.also {
33 it.values = searchableList
34 }
35 }
36
37 override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
38 // no need to use "results" filtered list provided by this method.
39 if (searchableList.isNullOrEmpty())
40 onNothingFound?.invoke()
41 notifyDataSetChanged()
42
43 }
44 }
45 }
46
47 interface Searchable {
48 /** This method will allow to specify a search string to compare against
49 your search this can be anything depending on your use case.
50 */
51 fun getSearchCriteria(): String
52 }
53
54
55}
انواع لیست که دارید باید اینترفیس Searchable را که در کلاس آداپتر فوق لیست شده پیادهسازی کنند تا قابلیت جستجو شدن را پیدا کنند. برای آشنایی با یک نوع از لیست SearchModel1 و SearchModel2 به مثالهای زیر توجه کنید:
1class SearchModel1(val data: String) : DynamicSearchAdapter.Searchable {
2
3
4 override fun getSearchCriteria(): String {
5 return data
6 }
7}
8class SearchModel2(val data: String) : DynamicSearchAdapter.Searchable {
9
10
11 override fun getSearchCriteria(): String {
12 return data
13 }
14}
لیستهای شما میتوانند مانند <List<SearchModel1 و <List<SearchModel2 باشند و همچنین باید یک کوئری جستجو بازگشت دهید که با متد getSearchCriteria هر کلاس مقایسه میشود. این متد برای فیلتر کردن دادههای هر لیست منفرد مورد استفاده قرار میگیرد. تا زمانی که الزامات فوق را رعایت کردهاید، میتوانید هر تعداد لیست که دوست دارید ایجاد نمایید. متد search میتواند برای تحریک جستجو روی لیست مورد استفاده قرار گیرد. متد search به صورت ناهمگام از سوی اینترفیس Filterable اندروید اجرا میشود و از جستجوی خطی با دو پارامتر بهره میگیرد:
- String: کوئری جستجو
- ?(Unit<-()): یک بدنه لامبدا برای فراخوانی در مواردی که هیچ نتیجهای برای جستجو یافت نشده است. از آن میتوان برای بهروزرسانی UI یا null استفاده کرد.
مثالی از یک اکتیویتی ساده مانند زیر کار میکند به این صورت است که کاربر دادهها را در نمای جستجو وارد میکند. در صورتی که هیچ نتیجهای مطابق ورودی در لیست پیدا نشود یک toast نمایش پیدا میکند.
1class SampleActivity2 : AppCompatActivity(), SearchView.OnQueryTextListener {
2
3
4 private lateinit var searchAdapter3: SearchAdapter3
5
6 override fun onCreate(savedInstanceState: Bundle?) {
7 super.onCreate(savedInstanceState)
8 setContentView(R.layout.fragment_main)
9 rv.layoutManager = LinearLayoutManager(this)
10 searchAdapter3 = SearchAdapter3(mutableListOf<SearchModel3>().populateWithUUIDSM3())
11 rv.adapter = searchAdapter3
12 searchV.setOnQueryTextListener(this)
13
14 }
15
16 override fun onQueryTextChange(newText: String?): Boolean {
17 search(newText)
18 return true
19 }
20
21 override fun onQueryTextSubmit(query: String?): Boolean {
22 search(query)
23 return true
24 }
25
26 private fun search(s: String?) {
27 searchAdapter3.search(s) {
28 // update UI on nothing found
29 Toast.makeText(this, "Nothing Found", Toast.LENGTH_SHORT).show()
30 }
31 }
شیوه اجرا
سورس کد این پروژه را میتوانید در این آدرس (+) ببینید. این سورس شامل یک اکتیویتی و 3 فرگمان به عنوان مثال است که همگی یک لیست قابل جستجو را با استفاده از یک recycler view نمایش میدهند. همچنین آداپترهایی دارند که آداپتر Dynamic Search را بسط میدهد. میتوانید این پروژه را در اندروید استودیو کلون کرده و اجرا نمایید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی اندروید
- گنجینه برنامهنویسی اندروید (Android)
- مجموعه آموزشهای برنامهنویسی
- RecyclerView با اسکرول روان در اندروید — راهنمای مقدماتی
- نکات کلیدی اندروید ۱۰ برای توسعه دهندگان — راهنمای کاربردی
==