iconifiedByDefault
속성을 사용해 밑줄쳐진 검색필드를 검색할 때만 활성화 시킬 수 있다.기본값은 true
이며, SeachView를 아이콘화 시키고 싶다면 해당 속성을 따로 입력하지 않아도 된다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetStart="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.SearchView
android:id="@+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/background_round_radius"
app:iconifiedByDefault="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:queryHint="@string/main_search_hint" />
</androidx.appcompat.widget.Toolbar>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/tabLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolBar" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@color/widget"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:tabIconTint="@color/selector_tab_icon_color"
app:tabIndicatorColor="#00ffffff" />
</androidx.constraintlayout.widget.ConstraintLayout>
OnQueryTextListener
는SearchView
에 문자를 입력하거나 검색 버튼을 눌렀을 때의 리스너다. 텍스트를 입력할 때마다 검색 기능을 사용할 목적이므로onQueryTextChange
만 사용한다.
private fun setOnQueryTextListener() {
binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener,
androidx.appcompat.widget.SearchView.OnQueryTextListener {
// 검색 버튼 입력시 호출, 검색 버튼이 없으므로 사용하지 않는다.
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
// 텍스트 입력, 수정시 호출
override fun onQueryTextChange(newText: String?): Boolean {
/*
* SearchView는 Activity 내에 구현했으며
* 입력 된 텍스트를 Fragment로 전달 하기 위한 함수
*/
updateItemCurrentFragment(newText)
return false
}
})
}
원본 리스트를 유지하고 필터링한 결과 리스트를 추가로 만들었다. 공백 또는 검색 기능을 사용하지 않을 때는 전체 리스트를 보여주기에 복제한 리스트의 초기값을 원본 리스트와 동일하게 선언한다.
class ContactAdapter(private var mItem: List<ContactViewType>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>(), Filterable {
private var filteredList: List<ContactViewType> = mItem
...
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
...
}
override fun getItemCount(): Int {
return filteredList.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = filteredList[position]) {
...
}
override fun getFilter(): Filter {
return object : Filter() {
// 입력 받은 문자열에 대한 처리
override fun performFiltering(constraint: CharSequence?): FilterResults {
val charString = constraint.toString().trim()
// 공백, 아무런 값이 입력 되지 않았을 때는 원본 리스트
filteredList = if (charString.isBlank()) {
mItem
} else {
val filterCondition: (ContactViewType) -> Boolean = { it ->
when (it) {
// 뷰 타입이 리스트일 때
is ContactViewType.ContactUser -> { // 이름, 전화 번호, 이메일 검색
it.user.name.contains(charString, true) ||
it.user.phone.contains(charString, true) ||
it.user.email.contains(charString, true)
}
// 뷰 타입이 그리드일 때
is GridUser -> { // 이름, 전화 번호, 이메일 검색
it.user.name.contains(charString, true) ||
it.user.phone.contains(charString, true) ||
it.user.email.contains(charString, true)
}
}
}
mItem.filter { filterCondition(it) }
}
// 검색 된 값으로 필터링 된 리스트
val filterResults = FilterResults().apply {
values = filteredList
}
return filterResults
}
// 처리에 대한 결과물
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
// FilterResults 값을 복사하고 값이 변경 되었으므로 adapter에 알린다.
filteredList = results?.values as List<ContactViewType>
notifyDataSetChanged()
}
}
}
// 검색 텍스트가 변경 되면 Fragment에서 호출 된다.
fun performSearch(query: String) {
filter.filter(query)
}