(Kotlin) SearchView를 이용한 RecyclerView filter 사용하기
- 안드로이드 개발/Kotlin으로 어플 만들기
- 2019. 8. 11. 20:02
이번 포스팅에서는 SearchView를 이용해서 RecyclerView의 데이터들을 검색하는 기능을 추가할 계획입니다.
우선 결과물부터 보겠습니다. 결과물이 굉장히 만족스럽네요.
이전 포스팅까지 만든 코드에서는 filter를 사용하려고 하니 굉장히 복잡하네요...
또다시 코드를 전면 수정했습니다. ㅠㅠ
코드 중간중간에 설명이 다 있습니다. 이대로 복! 붙! 하시면 됩니다.
1. Menu폴더 만들어주기
툴바의 검색 아이콘을 눌러 검색할 수 있도록 menu 폴더를 만들어 주겠습니다.
res 우클릭 → New 클릭 → Android Resource Directory를 눌러줍니다.
New Resource Directory 창이 뜨면,
Resource type을 menu로 바꿔주고 OK를 눌러주세요.
2. menu (menu_search.xml)
menu폴더 안에 menu_search.xml파일을 하나 만들어줍니다.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- hide share button by default -->
<item
android:id="@+id/menu_action_search"
android:icon="@drawable/ic_search"
android:title="Search"
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>
ic_search는 돋보기 아이콘인데, material icons 홈페이지에서 다운로드하여서 drawable 폴더에 넣어주세요.
링크는 아래 참고하세요.
https://material.io/resources/icons/?style=baseline
3. Kotlin (SearchAdapter.kt)
class SearchAdapter(private val context: Context, private val excelList: MutableList<SearchData>, private val listener: ItemClickListener) : RecyclerView.Adapter<SearchAdapter.SearchViewHolder>(), Filterable{
//검색기능을 위해서 별도의 List를 하나더 만들어주겠습니다.
private var excelSearchList: List<SearchData>? = null
//이너 클래스
inner class SearchViewHolder(view: View) : RecyclerView.ViewHolder(view){
//TextView 선언
val info: TextView
val quiz: TextView
init{
info = view.findViewById(R.id.search_info)
quiz = view.findViewById(R.id.search_quiz)
//온클릭리스너는 여기에!
view.setOnClickListener{
//여기서 !!의 의미는 nullable이면 오류가 발생하게 해줍니다. (?는 null)
listener.onItemClicked(excelSearchList!![adapterPosition])
}
}
}
//초기화 구문 init
init {
this.excelSearchList = excelList
}
//뷰홀더 생성
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder {
//리스트 아이템 인플레이터
val view = LayoutInflater.from(context).inflate(R.layout.search_list_item, parent, false)
return SearchViewHolder(view)
}
//온바인드뷰홀더 생성
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: SearchViewHolder, position: Int){
val excel = excelSearchList!![position]
//TextView에 excel 데이터 입력
holder.info.text = "#"+excel.fullname + " #"+excel.cate1+"("+excel.cate2+")" + " #"+excel.source
holder.quiz.text = excel.quiz.replace(".(?!$)".toRegex(), "$0\u200b")
}
//item 사이즈
override fun getItemCount(): Int = excelSearchList!!.size
//필터를 위한 코드
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults {
val charString = charSequence.toString()
if (charString.isEmpty()) {
excelSearchList = excelList
} else {
val filteredList = ArrayList<SearchData>()
//이부분에서 원하는 데이터를 검색할 수 있음
for (row in excelList) {
if (row.fullname.toLowerCase().contains(charString.toLowerCase()) || row.quiz.toLowerCase().contains(charString.toLowerCase())
|| row.cate2.toLowerCase().contains(charString.toLowerCase()) || row.source.toLowerCase().contains(charString.toLowerCase())) {
filteredList.add(row)
}
}
excelSearchList = filteredList
}
val filterResults = FilterResults()
filterResults.values = excelSearchList
return filterResults
}
override fun publishResults(charSequence: CharSequence, filterResults: FilterResults) {
excelSearchList = filterResults.values as ArrayList<SearchData>
notifyDataSetChanged()
}
}
}
interface ItemClickListener {
fun onItemClicked(item : SearchData)
}
}
자세히 확인해야 할 코드들..
- Filterable
- excelSearchList (이전에 excelList 부분을 바꿔줘야 합니다.)
- private var excelsearchList: List? = null
- override fun getFilter(): Filter {...}
'필터를 위한 코드'에서 빨간 줄 그이는 부분은 List의 이름이 다르거나 하는 경우일 거예요.
본인의 코드에 맞게 바꿔주세요.
2. Kotlin(SearchActivity.kt)
여기도 이대로 복!붙!
class SearchActivity : AppCompatActivity(),SearchAdapter.ItemClickListener {
private var recyclerView: RecyclerView? = null
private var itemlist: MutableList<SearchData> = mutableListOf()
private var mAdapter: SearchAdapter? = null
private var searchView: SearchView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.search)
val toolbar = findViewById(R.id.toolbar) as Toolbar
setSupportActionBar(toolbar)
val ab = supportActionBar!!
ab.setDisplayShowTitleEnabled(false)
ab.setDisplayHomeAsUpEnabled(true)
//정의
recyclerView = findViewById(R.id.search_recyclerview)
itemlist = ArrayList()
mAdapter = SearchAdapter(this, itemlist as ArrayList<SearchData>, this)
val mLayoutManager = LinearLayoutManager(applicationContext)
recyclerView!!.layoutManager = mLayoutManager
recyclerView!!.itemAnimator = DefaultItemAnimator()
recyclerView!!.adapter = mAdapter
//엑셀 불러오기
readExcelFileFromAssets()
}
//엑셀에서 가져온 데이터를 MutableList인 itemList에 추가해주고 Reutrn
private fun readExcelFileFromAssets(): MutableList<SearchData> {
try {
val myInput: InputStream
// assetManager 초기 설정
val assetManager = assets
// 엑셀 시트 열기
myInput = assetManager.open("hb.xls")
// POI File System 객체 만들기
val myFileSystem = POIFSFileSystem(myInput)
//워크 북
val myWorkBook = HSSFWorkbook(myFileSystem)
// 워크북에서 시트 가져오기
val sheet = myWorkBook.getSheetAt(0)
//행을 반복할 변수 만들어주기
val rowIter = sheet.rowIterator()
//행 넘버 변수 만들기
var rowno = 0
//행 반복문
while (rowIter.hasNext()) {
val myRow = rowIter.next() as HSSFRow
if (rowno != 0) {
//열을 반복할 변수 만들어주기
val cellIter = myRow.cellIterator()
//열 넘버 변수 만들기
var colno = 0
var item_no = ""
var year= ""
var exam = ""
var fullname = ""
var cate1 = ""
var cate2 = ""
var quiz = ""
var answer = ""
var source = ""
var explain = ""
var link = ""
//열 반복문
while (cellIter.hasNext()) {
val myCell = cellIter.next() as HSSFCell
if (colno === 0) {//no,
item_no = myCell.toString()
} else if (colno === 1) {//year,
year = myCell.toString()
} else if (colno === 2) {//exam,
exam = myCell.toString()
} else if (colno === 3) {//fullname,
fullname = myCell.toString()
} else if (colno === 4) {//cate1
cate1 = myCell.toString()
} else if (colno === 5) {//cate2
cate2 = myCell.toString()
} else if (colno === 6) {//quiz
quiz = myCell.toString()
} else if (colno === 7) {//answer
answer = myCell.toString()
} else if (colno === 8) {//source
source = myCell.toString()
} else if (colno === 9) {//explain
explain = myCell.toString()
} else if (colno === 10) {//link
link = myCell.toString()
}
colno++
}
//4,8번째 열을 Mutablelist에 추가
itemlist.add(SearchData(item_no, year, exam, fullname, cate1, cate2, quiz, answer, source, explain, link))
}
rowno++
}
} catch (e: Exception) {
Toast.makeText(this, "에러 발생", Toast.LENGTH_LONG).show()
}
return itemlist
}
//아이템 클릭시 TODO
override fun onItemClicked(item: SearchData) {
//여기에 원하는 코드 입력!!
val Intent = Intent(this, Search_Detail::class.java)
Intent.putExtra("fullname", item.fullname)
Intent.putExtra("cate1", item.cate1)
Intent.putExtra("cate2", item.cate2)
Intent.putExtra("quiz", item.quiz)
Intent.putExtra("answer", item.answer)
Intent.putExtra("source", item.source)
Intent.putExtra("explain", item.explain)
Intent.putExtra("link", item.link)
startActivity(Intent)
}
//우측상단메뉴
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.menu_search, menu)
var searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
searchView = menu.findItem(R.id.menu_action_search).actionView as SearchView
searchView!!.setSearchableInfo(searchManager.getSearchableInfo(componentName))
searchView!!.maxWidth = Integer.MAX_VALUE
searchView!!.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
mAdapter!!.filter.filter(query)
return false
}
override fun onQueryTextChange(query: String?): Boolean {
mAdapter!!.filter.filter(query)
return false
}
})
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
return if(id== R.id.menu_action_search) {
true
} else if(id==android.R.id.home){
finish()
true
} else super.onOptionsItemSelected(item)
}
override fun onBackPressed() {
// close search view on back button pressed
if (!searchView!!.isIconified) {
searchView!!.isIconified = true
return
}
super.onBackPressed()
}
}
끝.
'안드로이드 개발 > Kotlin으로 어플 만들기' 카테고리의 다른 글
(Kotlin) Card Flip Animation으로 Flashcard 만들기 (0) | 2019.08.15 |
---|---|
(Kotlin) Flip View(플립뷰)로 플래시카드 만들기 (0) | 2019.08.12 |
(Kotlin) RecyclerView, OnclickListener 사용하기 (3) | 2019.08.10 |
(Kotlin) Poi를 사용하여 엑셀 데이터 가져오기(2) (2) | 2019.08.07 |
(Kotlin) Poi를 사용하여 엑셀 데이터 가져오기(1) (5) | 2019.08.06 |