저번에 공부했던 SearchView 중 menu로 만든 SearchView 말고 public class SearchView를 통해 Filter를 구현해보고자 합니다.
우선 레이아웃은
<SearchView
android:id="@+id/searchView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:iconifiedByDefault="false"
android:paddingTop="5dp"
android:paddingBottom="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/searchView"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/post_item"/>
이런 식으로 listitem의 post_item은 저번 포스트에 RecyclerView의 listitem과 동일합니다.
먼저 Filter생성 전에 검색을 위한 data class Post를 작성해줍니다.
data class Post(
var no : Int, //post 순서
var email : String, //post 이메일
//var imageUri : String
)
email을 통해 검색을 시도하기 위해 data class 생성 후
Adapter를 생성합니다.
adapter는 RecyclerView를 생성하는 것 처럼 만들어주는데
중요한 점은
class PostContentAdapter (var post : ArrayList<Post>, var con : Context)
: RecyclerView.Adapter<PostContentAdapter.postViewHolder>(), Filterable {
위 처럼 Filterable를 작성해줍니다. 그런 후 멤버를 추가해 주고 난 후
//PostFilter()로 따로 filter함수 작성
var postFilter = PostFilter()
override fun getFilter(): Filter {
return postFilter
}
필터를 따로 함수로 작성해보도록 하겠습니다.
inner class PostFilter : Filter() {
// 입력받은 문자열에 대한 처리
override fun performFiltering(constraint: CharSequence): FilterResults {
val filterString = constraint.toString()
val results = FilterResults()
//검색이 필요없을 경우를 위해 원본배열 복제
val filterList : ArrayList<Post> = ArrayList<Post>()
//공벡제외 아무런 값도 입력하지 않았을 경우 ->원본배열
if (filterString.trim { it <= ' '}.isEmpty()) {
//필터링 작업으로 계산된 모든 값
results.values = post
//필터링 작업으로 계산된 값의 수
results.count = post.size
return results
//20글자 수 이하일 때 -> 이메일로 검색
} else if (filterString.trim {it <= ' '}.length <= 20) {
for (searchEmail in post) {
if (searchEmail.email.contains(filterString)) {
filterList.add(searchEmail)
}
}
}
results.values = filterList
results.count = filterList.size
return results
}
//처리에 대한 결과물
@SuppressLint("NotifyDataSetChanged")
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
filterPost.clear()
filterPost.addAll(results.values as ArrayList<Post>)
notifyDataSetChanged()
}
}
멤버 메소드 중 performFiltering, publishResults를 작성하는데 주석을 보시면 어떠한 곳에 쓰이는 지 알 수 있습니다.
여기서 CharSequence가 궁금했었는데 여기에서 자세히 확인 해볼 수 있습니다.
간단하게 적자면
String : String 객체에 입력되는 문자열 작성된 후 변경할 수 없으며, 문자열은 유니코드로 변형되므로 HTML과 같은 마크업 문자를 입출력할 때 문제가 발생한다. 이와 같이 마크업 문자를 입력하여 사용할 수 없기 때문에 변경할 수 없는 문자열이라고도 부릅니다.
CharSequence : CharSequence 객체에 보관하는 문자열은 같은 유니코드라도 마크업 문자를 사용할 수 있습니다.
그 다음으로 MainActivity에서 검색 버튼에 입력을 확인할 리스너를 만들기 위해 존재하는게 바로
setOnQueryTextListener 입니다. 자세한 것은 참조인 공식사이트에서 확인 하실 수 있습니다.
var searchViewTextListner : SearchView.OnQueryTextListener =
object :SearchView.OnQueryTextListener {
//검색버튼 입력시 호출하는데, 지금은 검색버튼이 없으므로 사용x
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
//텍스트 입력/수정 시 호출
override fun onQueryTextChange(s: String?): Boolean {
mAdapter!!.filter.filter(s)
return false
}
}
이메일 세팅
fun temp() : ArrayList<Post> {
var t = ArrayList<Post>()
t.add(Post(1, "wpqkf@gmail.com"))
t.add(Post(2, "ehofk@gmail.com"))
t.add(Post(3, "gngk@gmail.com"))
t.add(Post(4, "gmgl@gmail.com"))
return t
}
그 후 adapter연결, 데이터 세팅을 끝내고 실행을 하면
위 데이터 중 w를 가진 view만 나온 것을 확인할 수 있었습니다.
현재는 여기 코드를 따라하면서 이해하려 노력하고 있는데, 다음에는 공부한 내용을 바탕으로 저 만의 SearchView를 구현하도록 열심히 하겠습니다!