[Android] SearchView활용 recyclerview 검색
이번 포스팅에서는 recycler view를 사용한 리스트에서 특정 항목을 검색하여 해당 값들만 다시 출력하게 하는 검색기능을 구현하는 방법을 포스팅하겠습니다.
먼저 xml에 SerachView를 추가해줍니다. serachview에서 설정할수있는 값들은 아이콘, 힌트 등이있으며 별도로 포스팅하겠습니다.
<androidx.appcompat.widget.SearchView
android:id="@+id/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:iconifiedByDefault='false'
app:queryBackground="@color/gray"
app:searchIcon="@drawable/ic_baseline_search_24"
app:closeIcon="@drawable/ic_baseline_clear_24"
app:queryHint="해수욕장 검색"
android:maxWidth="200dp"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
/>
xml에 추가하였으면 이제 activity에 동작부를 추가하겠습니다. 저는 binding을 사용하기에 binding에 아까 추가한 searchView를 이어서 입력에 대한 리스너를 정의합니다. 그럼 2개의 함수를 override하게 되는데 상단의 onQueryTextSubmit은 최종 입력 후 엔터를 눌러야 반영되는 함수이며
onQueryTextChange는 입력이 실시간 반영되는 함수입니다.
이 입력값을 adapter에 구현한 filter를 통해 구현하였습니다.
binding.search.setOnQueryTextListener(object : SearchView.OnQueryTextListener,
androidx.appcompat.widget.SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
//검색 버튼 클릭되는 순간
return false
}
//검색어 입력중
override fun onQueryTextChange(newText: String?): Boolean {
findBeach = newText.toString()
communicationAdapter.filter.filter(newText)
Log.e(TAG,"검색어: $findBeach")
return false
}
})
recyclerView에 대한 adapter class 에서 Filterable또한 추가로 상속받습니다.
그럼 아래 getFirlter를 override해야하며 검색 결과리스트를 따로 연결하기에 기존 adpater에서 받는 리스트에 필터링할 리스트를 별도로 다시 정의하여 생성자 값을 넣어줍니다.
init {
filteredBeach.addAll(beaches)
}
inner class 를 통해 검색에 대한 기능을 구현합니다. 그리고 공백 혹은 글자수의 경우에 맞춰 필터링할 리스트에 검색어에 맞춰 값을 추가해줍니다.
//검색에 대한 필터링 함수
override fun getFilter(): Filter {
return itemFiler
}
inner class ItemFilter: Filter(){
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filterString = constraint.toString()
val results = FilterResults()
Log.d(TAG, "charSequence : $constraint")
//검색이 필요없을 경우를 위해 원본 배열을 복제
val filteredList: ArrayList<CombineBeachInfo> = ArrayList<CombineBeachInfo>()
//공백제외 아무런 값이 없을 경우 -> 원본 배열
if (filterString.trim { it <= ' ' }.isEmpty()) {
results.values = beaches
results.count = beaches.size
return results
//공백제외 2글자 이인 경우 -> 이름으로만 검색
} else if (filterString.trim { it <= ' ' }.length <= 2) {
for (i in beaches) {
if (i.poiNm.contains(filterString)) {
filteredList.add(i)
}
}
}
results.values = filteredList
results.count = filteredList.size
return results
}
@SuppressLint("NotifyDataSetChanged")
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
filteredBeach.clear()
filteredBeach.addAll(results.values as ArrayList<CombineBeachInfo>)
notifyDataSetChanged()
}
}
publishResults에서 출력할 리스트의 값을 다 지우고 검색어에 해당되는 리스트를 다시 추가하여 변경하여줍니다.