all element are responsible for the search worked normal. the list just does not want to change. maybe someone know how this work i searched some information on internet but alas not found
Main Activity
class MainActivity : AppCompatActivity() {
var searchView:SearchView?=null
lateinit var adapter: ProductListAdapter
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.menu_item_list, menu)
adapter = ProductListAdapter(applicationContext)
val searchManager = getSystemService(Context.SEARCH_SERVICE)as SearchManager
searchView = menu!!.findItem(R.id.action_search).actionView as SearchView
searchView!!.setSearchableInfo(searchManager.getSearchableInfo(componentName))
searchView!!.maxWidth = Int.MAX_VALUE
searchView!!.setOnQueryTextListener(object:SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
adapter.filter.filter(query)
Toast.makeText(this#MainActivity,"Work onQueryTextSubmit",Toast.LENGTH_SHORT).show()
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
adapter.filter.filter(newText)
Toast.makeText(this#MainActivity,"onQueryTextChange",Toast.LENGTH_SHORT).show()
return true
}
})
return super.onCreateOptionsMenu(menu)
}
}
maybe i have problem in adapter of recycler view i dont understand
i think i have problem with filterListAdapter list because in my example they are emptylist?
Adapter
class ProductListAdapter internal constructor(
context: Context
) : RecyclerView.Adapter<ProductListAdapter.ProductViewHolder>(), Filterable {
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var productsList = emptyList<ProductEntity>()
internal var filterListResult: List<ProductEntity>
init {
this.filterListResult = productsList
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val charSearch = constraint.toString()
if (charSearch.isEmpty())
filterListResult = productsList
else {
val resultList = ArrayList<ProductEntity>()
for(row in productsList){
if (row.productName!!.toLowerCase().contains(charSearch.toLowerCase()))
resultList.add(row)
}
filterListResult = resultList
}
val filterResults = FilterResults()
filterResults.values = filterListResult
return filterResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
filterListResult = results!!.values as List<ProductEntity>
notifyDataSetChanged()
}
}
}
override fun getItemCount(): Int {
var sizes = filterListResult.size
return sizes
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int)
{
holder.onBind(productsList[position])
holder.onBind(filterListResult[position])
}
class ProductViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val productName = view.product_name
private val productPrice = view.product_price
private val productWeight = view.product_weight
fun onBind(productEntity: ProductEntity) {
productName.text = productEntity.productName
productPrice.text = productEntity.productPrice.toString()
productWeight.text = productEntity.productWeight.toString()
}
}
internal fun setAll(productEntity: List<ProductEntity>) {
this.productsList = productEntity
this.filterListResult = productEntity
notifyDataSetChanged()
}
}
Related
I am trying to filter my recyclerview using filterable, it works fine on static data, but on dynamic data from firestore
First, I got the data from Firestore in arrayList
Then, I filter those arrayList to new arrayList
But when any change happended in Firestore, the original arrayList will be updated and my recyclerview will display this data instead the data I currently filltered on searchview
What I wanted to do is my recyclerview to aslway display filtered data when I type any word on searchview whether they are any updated data or not
added screenshot
here is my adapter
class SearchAdapter() : RecyclerView.Adapter<SearchAdapter.ListViewHolder>(), Filterable {
private var listSearch = ArrayList<Dosen>()
private var listSearchFull = ArrayList<Dosen>()
fun setData(list: ArrayList<Dosen>){
this.listSearch = list
listSearchFull = ArrayList(listSearch)
}
inner class ListViewHolder(itemView: UserListBinding) : RecyclerView.ViewHolder(itemView.root) {
private val binding = itemView
fun bind(dosen: Dosen) {
with(binding){
val db = Firebase.firestore
val collection = db.collection("alat")
.whereEqualTo("id", dosen.alat_id)
collection.get()
.addOnSuccessListener { document ->
try {
val location = document.toObjects(Alat::class.java)[0].lokasi
tvLocation.text = location
} catch (e: Exception){
Log.d("rv", "system error $e")
}
}
.addOnFailureListener { exception ->
Log.d("rv", "get failed with ", exception)
}
tvUsername.text = dosen.nama
val simpleDateFormat = SimpleDateFormat("EEEE, dd LLLL yyyy")
val date = simpleDateFormat.format(dosen.datetime!!.toDate())
Log.d("rvTime", date)
tvDate.text = date
val simpleTimeFormat = SimpleDateFormat("KK:mm:ss aaa")
val time = simpleTimeFormat.format(dosen.datetime.toDate())
Log.d("rvTime", time)
tvTime.text = time
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
return ListViewHolder(UserListBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
holder.bind(listSearch[position])
}
override fun getItemCount(): Int = listSearch.size
override fun getFilter(): Filter {
return object : Filter(){
override fun performFiltering(query: CharSequence?): FilterResults {
val filteredList: ArrayList<Dosen> = ArrayList()
if (query == null || query.length == 0){
filteredList.addAll(listSearchFull)
} else{
val searchQuery = query.toString().toLowerCase().trim()
for (item in listSearchFull) {
if (item.nama!!.lowercase(Locale.ROOT).contains(searchQuery)){
filteredList.add(item)
}
}
}
val filterResults = FilterResults()
filterResults.values = filteredList
return filterResults
}
override fun publishResults(query: CharSequence?, filteredResult: FilterResults?) {
//error
listSearch.clear()
listSearch.addAll(filteredResult!!.values as ArrayList<Dosen>)
notifyDataSetChanged()
}
}
}
}
and here is my fragment
class SearchFragment : Fragment() {
private var _binding: FragmentSearchBinding? = null
private val binding get() = _binding!!
private lateinit var searchAdapter: SearchAdapter
private lateinit var searchArrayList : ArrayList<Dosen>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentSearchBinding.inflate(inflater, container, false)
val root: View = binding.root
searchArrayList = arrayListOf()
#Suppress("DEPRECATION")
setHasOptionsMenu(true)
eventChangeListener()
return root
}
private fun eventChangeListener() {
val db = Firebase.firestore
db.collection("presensi")
.orderBy("datetime", Query.Direction.DESCENDING)
.addSnapshotListener(object : EventListener<QuerySnapshot>{
override fun onEvent(value: QuerySnapshot?, error: FirebaseFirestoreException?) {
searchArrayList.clear()
for (document in value!!){
searchArrayList.add(document.toObject(Dosen::class.java))
searchAdapter.setData(searchArrayList)
Log.d("arraySearch", document.toObject<Dosen>().toString())
Log.d("arraySearchList", searchArrayList.toString())
}
searchAdapter.notifyDataSetChanged()
}
})
searchAdapter = SearchAdapter()
with(binding){
tvNoData.visibility = View.GONE
rvSearch.layoutManager = LinearLayoutManager(activity)
rvSearch.setHasFixedSize(true)
rvSearch.adapter = searchAdapter
}
}
/// prob need fix
#Deprecated("Deprecated in Java")
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
#Suppress("DEPRECATION")
super.onCreateOptionsMenu(menu, inflater)
menu.clear()
inflater.inflate(R.menu.main_menu, menu)
val searchView = context?.let { SearchView(it) }
menu.findItem(R.id.menu_search).apply {
setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW or MenuItem.SHOW_AS_ACTION_IF_ROOM)
actionView = searchView
}
searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
searchAdapter.filter.filter(newText)
return false
}
})
}
override fun onStart() {
super.onStart()
Log.d("firebaseFirestoreListener", "onStart")
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
Log.d("firebaseFirestoreListener", "onDestroyView")
}
}
Is it actually possible to do what I want?
or should I use 3rd party library like algolia, but it's not free.
I hope you guys understand my question
I did my adapter and made a function that would filter my list. But the issue is that it's no showing the results and i don't know why. There 2 lists: one of them is full list and the other one is the filtered list. Here is my adapter:
class SearchAdapter : RecyclerView.Adapter<SearchViewHolder>(), Filterable {
var fullInstitutionData: ArrayList<InstitutionModel> = ArrayList()
var institutionData: ArrayList<InstitutionModel> = ArrayList()
init {
institutionData = ArrayList()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder {
val inflater = LayoutInflater.from(parent.context)
return SearchViewHolder(inflater, parent)
}
override fun getItemCount(): Int = institutionData.size
override fun onBindViewHolder(holder: SearchViewHolder, position: Int) {
val dialogData: InstitutionModel = institutionData[position]
holder.bind(dialogData)
}
override fun getFilter(): Filter {
return customFilter
}
fun addDataFromClient(listDataClient: ArrayList<InstitutionModel>) {
institutionData.addAll(listDataClient)
fullInstitutionData = ArrayList(listDataClient)
notifyDataSetChanged()
}
private val customFilter = object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList = arrayListOf<InstitutionModel>()
if (constraint == null || constraint.length == 0) {
filteredList.addAll(institutionData)
} else {
val filterPattern = constraint.toString().toLowerCase().trim()
for (item in fullInstitutionData) {
if (item.name.toLowerCase().contains(filterPattern) || item.name?.toLowerCase()!!
.contains(filterPattern)) {
filteredList.add(item)
}
}
}
val results = FilterResults()
results.values = filteredList
return results
}
override fun publishResults(constraint: CharSequence?, filterResults: FilterResults?) {
institutionData.clear()
institutionData.addAll(filterResults?.values as MutableList<InstitutionModel>)
}
}
}
And this is my search function that i did the setOnQueryListener in the my fragment:
fun searchInstitution() {
searchViewInstitutions.apply {
setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
searchAdapter.filter.filter(newText)
return false
}
})
}
}
This is the code when i call the recyclerview on onActivityCreated:
val llm = LinearLayoutManager(context)
llm.orientation = LinearLayoutManager.VERTICAL
rvSearch.layoutManager = llm
rvSearch.adapter = SearchAdapter()
searchAdapter.addDataFromClient(data)
searchInstitution()
There are two fixes needed:
notifyDataSetChanged() when you publishResults()
override fun publishResults(constraint: CharSequence?, filterResults: FilterResults?) {
institutionData.clear()
institutionData.addAll(filterResults?.values as MutableList<InstitutionModel>)
notifyDataSetChanged() // <<< Change Here
}
Add the full list when there is no match instead of the filtered one
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList = arrayListOf<InstitutionModel>()
if (constraint == null || constraint.length == 0) {
filteredList.addAll(fullInstitutionData) // <<< Change Here
I'm referring to this tutorial.
Everything runs fine without error but its not filtering
when I type anything. It is not filtering the list.
I don't know what I'm doing wrong.
The following is my adapter and activity code.
Adapter code
class Table_Adapter(val context: Context) : RecyclerView.Adapter<Table_Adapter.MyViewHolder>(),Filterable {
var mFilteredList: MutableList<Tabledata> = mutableListOf()
var Tablelist: MutableList<Tabledata> = mutableListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(
R.layout.table_recycle_item,
parent,
false
)
return MyViewHolder(view)
}
override fun getItemCount(): Int {
return Tablelist.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.productname.text = Tablelist.get(position).name
holder.producername.text = Tablelist.get(position).producer
holder.productprice.text = Tablelist.get(position).cost.toString()
Glide.with(context).load(Tablelist.get(position).product_images)
.into(holder.image)
holder.rate.setRating(Tablelist.get(position).rating.toFloat());
holder.itemView!!.setOnClickListener {
val context:Context=holder.itemView.context
val i=Intent(
context,
Product_details::class.java
)
i.putExtra("id", Tablelist.get(position).id.toString())
i.putExtra("image", Tablelist.get(position).product_images)
context.startActivity(i)
}
}
fun setMovieListItems(movieList: MutableList<Tabledata>){
this.Tablelist = movieList;
notifyDataSetChanged()
}
class MyViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView!!) {
val productname: TextView = itemView!!.findViewById(R.id.title)
val producername: TextView = itemView!!.findViewById(R.id.title1)
val productprice: TextView = itemView!!.findViewById(R.id.title2)
val rate: RatingBar=itemView!!.findViewById(R.id.ratingbar)
val image: ImageView = itemView!!.findViewById(R.id.image)
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults? {
val charString = charSequence.toString()
if (charString.isEmpty()) {
mFilteredList = Tablelist
} else {
val filteredList: MutableList<Tabledata> = ArrayList()
for (androidVersion in Tablelist) {
/* if (androidVersion.name.toLowerCase()
.contains(charString)
) {
filteredList.add(androidVersion)
}*/
if (androidVersion.name.toLowerCase()
.contains(charString.toLowerCase()) || androidVersion.name
.contains(charSequence)
) {
filteredList.add(androidVersion)
}
}
mFilteredList = filteredList
}
val filterResults = FilterResults()
filterResults.values = mFilteredList
return filterResults
}
override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults) {
mFilteredList = filterResults.values as MutableList<Tabledata>
notifyDataSetChanged()
}
}
}
}
Activity:
class Tables : AppCompatActivity() {
lateinit var recyclerView: RecyclerView
lateinit var recyclerAdapter: Table_Adapter
var Tablelist : MutableList<Tabledata> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.table_activity)
var mActionBarToolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbartable);
setSupportActionBar(mActionBarToolbar);
if (getSupportActionBar() != null){
getSupportActionBar()?.setDisplayHomeAsUpEnabled(true);
getSupportActionBar()?.setDisplayShowHomeEnabled(true);
getSupportActionBar()?.setHomeAsUpIndicator(R.drawable.ic_keyboard_arrow_left_black_24dp);
getSupportActionBar()?.setTitle((Html.fromHtml("<font color=\"#FFFFFF\">" + getString(R.string.Tables) + "</font>")));
}
recyclerView = findViewById(R.id.recyleview)
recyclerAdapter = Table_Adapter(this)
recyleview.layoutManager = LinearLayoutManager(this)
recyclerView.addItemDecoration(
DividerItemDecoration(
recyclerView.context,
DividerItemDecoration.VERTICAL
)
)
recyleview.adapter = recyclerAdapter
RetrofitClient.instancetable.getAllPhotos(product_category_id = "1", value = 1).enqueue(
object : Callback<Table_response> {
override fun onFailure(call: Call<Table_response>, t: Throwable) {
Toast.makeText(applicationContext, "falied", Toast.LENGTH_LONG).show()
}
override fun onResponse(
call: Call<Table_response>,
response: Response<Table_response>
) {
if (response?.body() != null) {
recyclerAdapter.setMovieListItems((response.body()?.data as MutableList<Tabledata>?)!!)
}
}
})
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
NavUtils.navigateUpFromSameTask(this)
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
val search: MenuItem = menu.findItem(R.id.search)
val searchView: SearchView = MenuItemCompat.getActionView(search) as SearchView
search(searchView)
return true
}
override fun onBackPressed() {
super.onBackPressed()
}
private fun search(searchView: SearchView) {
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
recyclerAdapter.getFilter().filter(newText)
return true
}
})
}
}
Thanks in advance.
Search view queries do not result in a filtered list because you are not using the filtered list.
onBindViewHolder and getItemCount uses only Tablelist variable. mFilteredList only holds filtered results - not uses them.
Store original list as you do it currently, but replace the use of Tablelist with mFilteredList in onBindViewHolder and getItemCount. Also, a minor update in setMovieListItems is required. mFilteredList is also declared as unmutable. performFiltering also was improved a little bit and is not shorter. Everything is presented below:
class Table_Adapter() : RecyclerView.Adapter<Table_Adapter.MyViewHolder>(), Filterable {
var mFilteredList: List<Tabledata> = listOf()
var tableList: MutableList<Tabledata> = mutableListOf()
...
override fun getItemCount(): Int {
return mFilteredList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val tableItem = mFilteredList.get(position)
holder.productname.text = tableItem.name
holder.producername.text = tableItem.producer
holder.productprice.text = tableItem.cost.toString()
Glide.with(holder.itemView!!.context).load(tableItem.product_images)
.into(holder.image)
holder.rate.setRating(tableItem.rating.toFloat());
holder.itemView!!.setOnClickListener {
val context: Context = holder.itemView.context
val i = Intent(
context,
Product_details::class.java
)
i.putExtra("id", tableItem.id.toString())
i.putExtra("image", tableItem.product_images)
context.startActivity(i)
}
}
fun setMovieListItems(movieList: MutableList<Tabledata>) {
tableList = movieList.toMutableList() // makes a copy
mFilteredList = movieList
notifyDataSetChanged()
}
...
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults? {
val queryString = charSequence.toString()
val filterResults = FilterResults()
filterResults.values =
if (queryString.isEmpty()) {
tableList
} else {
tableList.filter {
it.name.contains(queryString, ignoreCase = true) || it.name.contains(charSequence)
}
}
return filterResults
}
override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults) {
mFilteredList = filterResults.values
notifyDataSetChanged()
}
}
}
}
I have implemented searchView with recyclerView it is not working and giving errors I did not understand where I am making mistakes. below my MainActivity where I have implemented searchview logic
I have implemented searchView with recyclerView it is not working and giving errors I did not understand where I am making mistakes. below my MainActivity where I have implemented searchview logic
class MemberActivity : AppCompatActivity() {
private var memberAdapter: MemberAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_member)
val compositeDisposable = CompositeDisposable()
compositeDisposable.add(
ServiceBuilder.buildService(SpectrumInterface::class.java)
.getMembers()
.toObservable()
.flatMap { Observable.fromIterable(it) }
.flatMap { Observable.fromIterable(it.members) }
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ members -> onResponse(members) },
{ t -> onFailure(t) })
)
memberAdapter = MemberAdapter()
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL))
private fun onFailure(t: Throwable) {
Toast.makeText(this, t.message, Toast.LENGTH_SHORT).show()
}
private fun onResponse(members: List<Member>) {
progressBar.visibility = View.GONE
(recyclerView.adapter as MemberAdapter).setMembers(members)
}
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
memberAdapter?.getFilter()?.filter(newText)
return true
}
ascendingButton.setOnClickListener
{
memberAdapter?.sortAscending()
}
descendingButton.setOnClickListener {
memberAdapter?.sortDescending()
}
}
}
below my Adapter where I have implemented filter logic
class MemberAdapter : RecyclerView.Adapter<MemberAdapter.MemberViewHolder>() {
private val members = mutableListOf<Member>()
fun setMembers(data: List<Member>) {
members.clear()
members.addAll(data)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MemberViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.member_list, parent, false)
return MemberViewHolder(view)
}
override fun getItemCount() = members.size
fun sortAscending() {
members.sortBy { it.age }
notifyDataSetChanged()
}
fun sortDescending() {
members.sortByDescending { it.age }
notifyDataSetChanged()
}
fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults {
val query = charSequence.toString()
val filtered: MutableList<Member> = ArrayList()
if (query.isEmpty()) {
filtered.clear()
filtered.addAll(members)
} else {
filtered.addAll(members.filter {
it.id.toLowerCase(Locale.ROOT)
.contains(query.toLowerCase(Locale.ROOT)) || it.age.toString()
.contains(query)
})
}
val results = FilterResults()
results.count = filtered.size
results.values = filtered
return results
}
override fun publishResults(charSequence: CharSequence, results: FilterResults) {
members.clear()
members.addAll(results.values as Collection<Member>)
notifyDataSetChanged()
}
}
}
override fun onBindViewHolder(holder: MemberViewHolder, position: Int) {
return holder.bind(members[position])
}
class MemberViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val memberAge: TextView = itemView.findViewById(R.id.memberAge)
// private val memberName: TextView = itemView.findViewById(R.id.memberName)
private val lastName: TextView = itemView.findViewById(R.id.lastName)
private val firstName: TextView = itemView.findViewById(R.id.firstName)
private val emailAddress: TextView = itemView.findViewById(R.id.emailAddress)
private val phone: TextView = itemView.findViewById(R.id.phone)
fun bind(member: Member) {
memberAge.text = member.age.toString()
lastName.text = member.name?.last
firstName.text = member.name?.first
emailAddress.text = member.email
phone.text = member.phone
}
}
}
Your mistake is updating members and then using it again as your base for future filtering.
Instead:
Create another list filteredMembers in MembersAdapter, initialize it to be equal to members in setMembers()
Make MembersAdapter reflect the items in filteredMembers
override fun getItemCount() = filteredMembers.size
override fun onBindViewHolder(holder: MemberViewHolder, position: Int) {
return holder.bind(filteredMembers[position])
}
Make your filter update filteredMembers and not members
I'm trying to implement search option in recyclerview.
What I have implemented so far is:
created a search bar as below:
I've applied onCreateOptions as per below in MainActivity:
class RecyclerListActivity: AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: PostListViewModel
private var errorSnackbar: Snackbar? = null
private var searchView: SearchView? = null
override fun onCreate(savedInstanceState: Bundle?){
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.postList.layoutManager = GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false)
viewModel = ViewModelProviders.of(this).get(PostListViewModel::class.java)
viewModel.errorMessage.observe(this, Observer {
errorMessage -> if(errorMessage != null) showError(errorMessage) else hideError()
})
binding.viewModel = viewModel
}
private fun showError(#StringRes errorMessage:Int){
errorSnackbar = Snackbar.make(binding.root, errorMessage, Snackbar.LENGTH_INDEFINITE)
errorSnackbar?.setAction(R.string.retry, viewModel.errorClickListener)
errorSnackbar?.show()
}
private fun hideError(){
errorSnackbar?.dismiss()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
searchView = menu.findItem(R.id.action_search).actionView as SearchView
searchView!!.maxWidth = Int.MAX_VALUE
searchView!!.imeOptions = EditorInfo.IME_ACTION_DONE
// listening to search query text change
searchView!!.setOnQueryTextListener(object :
SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(query: String): Boolean {
return false
}
})
return true
}
}
My Adapter class as below:
class PostListAdapter: RecyclerView.Adapter<PostListAdapter.ViewHolder>(), Filterable {
private lateinit var postList:List<Data>
private lateinit var postListFull:List<Data>
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding: ListItemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.context), R.layout.list_item, parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(postList[position])
}
override fun getItemCount(): Int {
return if(::postList.isInitialized) postList.size else 0
}
fun updatePostList(postList:List<Data>){
this.postList = postList
notifyDataSetChanged()
}
class ViewHolder(private val binding: ListItemBinding): RecyclerView.ViewHolder(binding.root){
private val viewModel = MoviesViewModel()
fun bind(post:Data){
viewModel.bind(post)
binding.viewModel = viewModel
}
init {
binding.root.setOnClickListener {
//Toast.makeText(binding.root.context, binding.postTitle.text, Toast.LENGTH_SHORT).show()
val intent = Intent(binding.root.context, DetailsActivity::class.java)
//intent.putExtra(REPO_NAME, binding.postTitle.text)
binding.root.context.startActivity(intent)
}
}
}
override fun getFilter(): Filter? {
return searchFilter
}
private val searchFilter: Filter = object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults? {
val filteredList: MutableList<Data> = ArrayList()
if (constraint == null || constraint.isEmpty()) {
filteredList.addAll(postListFull)
} else {
val filterPattern =
constraint.toString().toLowerCase().trim()
for (item in postListFull) {
if (item.title.toLowerCase().contains(filterPattern) || item.genre.toLowerCase().contains(filterPattern)) {
filteredList.add(item)
}
}
}
val results = FilterResults()
results.values = filteredList
return results
}
override fun publishResults(
constraint: CharSequence?,
results: FilterResults
) {
//postList.clear()
//postList.addAll(results.values as List<*>)
notifyDataSetChanged()
}
}
I have two issues here to resolve it. first one is: getting unresolved reference in these lines (Adapter class). How could I resolve it?
postList.clear()
postList.addAll(results.values as List<*>)
second one is: how to apply the filter results in adapter as I've used dagger & databinding? I've used following tutorial to create recyclerview: https://proandroiddev.com/mvvm-with-kotlin-android-architecture-components-dagger-2-retrofit-and-rxandroid-1a4ebb38c699
private lateinit var postListFull: ArrayList<Data>= ArrayList()
in the publishResults() method, to store the result in list :
postListFull= results!!.values as ArrayList<Data>
notifyDataSetChanged()
for your second issue, where do you want to apply the filter results and why?