본문 바로가기

Android/Function

[Kotlin] 검색 필터링과 아이템 클릭 가능한 RecyclerView 만들기

728x90
반응형

 

예제 소개

  • 특정 파일의 이름을 RecylcerView에 띄우기
  • EditText를 통해 문자를 입력시 필터
  • 특정 RecyclerView Item 클릭 (Item Click Listener)

 

문자열 입력시 필터 가능한 RecyclerView 만들기


 

  • FileListAdapter.kt
class FileListAdapter internal constructor(val context: Context, val fileList: ArrayList<String>?)
    : RecyclerView.Adapter<FileListAdapter.FileViewHolder>(), Filterable {

	//필터링을 위해 필요한 변수
    private var files: ArrayList<String>? = fileList

    inner class FileViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val str: TextView = itemView.an_str

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FileViewHolder {
        val itemView = LayoutInflater.from(context).inflate(R.layout.analytics_item, parent, false)
        return FileViewHolder(itemView)

    }

    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: FileViewHolder, position: Int) {
        val current = files?.get(position)
        holder.str.text = current
    }


    override fun getItemCount() = files?.size!!

    override fun getFilter(): Filter? {
        return object : Filter() {
            override fun performFiltering(constraint: CharSequence): FilterResults {
                val charString = constraint.toString()
                files = if (charString.isEmpty()) {
                    fileList
                } else {
                    val filteredList = ArrayList<String>()
                    if (fileList != null) {
                        for (name in fileList) {
                            if(name.toLowerCase().contains(charString.toLowerCase())) {
                                filteredList.add(name);
                            }
                        }
                    }
                    filteredList
                }
                val filterResults = FilterResults()
                filterResults.values = files
                return filterResults
            }

            override fun publishResults(constraint: CharSequence, results: FilterResults) {
                files  = results.values as ArrayList<String>
                notifyDataSetChanged()
            }
        }
    }


}

 

Recyclerview에  Filterable을 implements하여  getFilter() 메서드를 통해 필터 가능한 리사이클러뷰를 만들 수 있습니다.

Adpater 생성시 변수로 리스트를 받아와 넣어줍니다.

 

  • Main
val files = viewModel.getFiles()

if(files!=null) {
     mAdapter = mApplicationContext?.let { FileListAdapter(it, files) }
}

an_recyclerView.apply {
     adapter = mAdapter
     layoutManager = LinearLayoutManager(mApplicationContext)
}


an_search_text.addTextChangedListener (object: TextWatcher{
      override fun beforeTextChanged(charSequence: CharSequence?, p1: Int, p2: Int, p3: Int) {
           //Do Nothing
      }
      override fun onTextChanged(charSequence: CharSequence?, p1: Int, p2: Int, p3: Int) {
           mAdapter?.filter?.filter(charSequence)
      }
      override fun afterTextChanged(charSequence: Editable?) {
           //Do Nothing
      }

   }

)

EditText의  addTextChangeListener를 추가하여 텍스트가 바뀔때마다 adapter를 갱신해줍니다.

 


 

RecyclerView ItemClickListener 추가하기


Adapter에 변수와 메서드를 밑과 같이 추가해 줍니다.

private lateinit var itemClickListner: ItemClickListener

...

interface ItemClickListener {
    fun onClick(view: View, position: Int)
}
fun setItemClickListener(itemClickListener: ItemClickListener) {
    this.itemClickListner = itemClickListener
}

 

onBindViewHoldersetOnClickLister를 추가합니다.

holder.itemView.setOnClickListener {
   itemClickListner.onClick(it, position)
}

 

 

Main에서 밑과 같이 사용할수 있습니다.

 mAdapter?.setItemClickListener(object : FileListAdapter.ItemClickListener {
     override fun onClick(view: View, position: Int) {
          Log.d("onClick", "Click! Item $position")
     }
})

 


전체 코드


class FileListAdapter internal constructor(val context: Context, val fileList: ArrayList<String>?)
    : RecyclerView.Adapter<FileListAdapter.FileViewHolder>(), Filterable {

    private var files: ArrayList<String>? = fileList
    private lateinit var itemClickListner: ItemClickListener

    inner class FileViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val str: TextView = itemView.an_str

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FileViewHolder {
        val itemView = LayoutInflater.from(context).inflate(R.layout.analytics_item, parent, false)
        return FileViewHolder(itemView)

    }

    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: FileViewHolder, position: Int) {
        val current = files?.get(position)
        holder.str.text = current

        holder.itemView.setOnClickListener {
            itemClickListner.onClick(it, position)
        }

    }


    override fun getItemCount() = files?.size!!

    override fun getFilter(): Filter? {
        return object : Filter() {
            override fun performFiltering(constraint: CharSequence): FilterResults {
                val charString = constraint.toString()
                files = if (charString.isEmpty()) {
                    fileList
                } else {
                    val filteredList = ArrayList<String>()
                    if (fileList != null) {
                        for (name in fileList) {
                            if(name.toLowerCase().contains(charString.toLowerCase())) {
                                filteredList.add(name);
                            }
                        }
                    }
                    filteredList
                }
                val filterResults = FilterResults()
                filterResults.values = files
                return filterResults
            }

            override fun publishResults(constraint: CharSequence, results: FilterResults) {
                files  = results.values as ArrayList<String>
                notifyDataSetChanged()
            }
        }
    }

    interface ItemClickListener {
        fun onClick(view: View, position: Int)
    }
    fun setItemClickListener(itemClickListener: ItemClickListener) {
        this.itemClickListner = itemClickListener
    }

}

 

val files = viewModel.getFiles()

        if(files!=null) {
            mAdapter = mApplicationContext?.let { FileListAdapter(it, files) }
        }

        an_recyclerView.apply {
            adapter = mAdapter
            layoutManager = LinearLayoutManager(mApplicationContext)
        }


        an_search_text.addTextChangedListener (object: TextWatcher{
            override fun beforeTextChanged(charSequence: CharSequence?, p1: Int, p2: Int, p3: Int) {
                //Do Nothing
            }
            override fun onTextChanged(charSequence: CharSequence?, p1: Int, p2: Int, p3: Int) {
                mAdapter?.filter?.filter(charSequence)

            }
            override fun afterTextChanged(charSequence: Editable?) {
                //Do Nothing
            }
            }
        )

        mAdapter?.setItemClickListener(object : FileListAdapter.ItemClickListener {
            override fun onClick(view: View, position: Int) {
                Log.d("onClick", "Click! Item $position")
            }
        })

    }

 

 

 

 

 

728x90
반응형