RecyclerView is using a spinner.
For example, if you have three items,
The second item is made of TEMP through a spinner. (The default is test.)
EX)
test
temp
test
When the delete button of the first position is pressed,
I want the contents I want to be displayed as below.
test
test
But in reality,
test
temp
I deleted the temp, but why does the temp keep being exposed?
What should I do?
RecycleItemadapter.kt
#SuppressLint("MissingPermission") class RecycleItemAdapter(val calculateWeight: (MutableList<RecycleDropDownData>, Int) -> Unit,
private val itemList: MutableList<RecycleDropDownData>) : RecyclerView.Adapter<RecycleItemAdapter.DevicesAdapterViewHolder>() {
private var recycleItemList = mutableListOf<RecycleDropDownData>()
#SuppressLint("NewApi")
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DevicesAdapterViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_recycler, parent, false)
return DevicesAdapterViewHolder(view)
}
#SuppressLint("RecyclerView", "NotifyDataSetChanged")
override fun onBindViewHolder(holder: DevicesAdapterViewHolder, pos: Int) {
holder.recycleItem.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val weight = recycleItemList[pos].weight
recycleItemList[pos] = itemList[position]
recycleItemList[pos].weight = weight
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
holder.recycleWeight.text = recycleItemList[pos].weight
// TODO
holder.recycleDelete.setOnClickListener {
recycleItemList.removeAt(pos)
notifyDataSetChanged()
}
}
fun setData(recyclerList: MutableList<RecycleDropDownData>) {
this.recycleItemList = recyclerList
}
fun getData(): MutableList<RecycleDropDownData> {
return recycleItemList
}
override fun getItemCount(): Int {
return recycleItemList.size
}
inner class DevicesAdapterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val recycleWeight: TextView
private val recycleCalculate: Button
val recycleDelete: Button
val recycleItem: Spinner
init {
recycleItem = itemView.findViewById(R.id.recycle_item_spinner)
recycleItem.adapter = ArrayAdapter(itemView.context, R.layout.item_drop_down, itemList)
recycleWeight = itemView.findViewById(R.id.recycler_item_weight)
recycleCalculate = itemView.findViewById(R.id.recycler_item_weight_calculate)
recycleDelete = itemView.findViewById(R.id.recycler_item_delete)
}
}
}
item_recycler
<Spinner
android:id="#+id/recycle_item_spinner"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="#layout/item_drop_down" />
<TextView
android:id="#+id/recycler_item_weight"
android:layout_width="100dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#id/recycle_item_spinner"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/recycler_item_weight_calculate"
style="#style/station_detail_item_passenger_button"
android:background="#color/color_mint_code_75f8ff"
android:text="무게"
app:layout_constraintLeft_toRightOf="#id/recycler_item_weight"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/recycler_item_delete"
style="#style/station_detail_item_passenger_button"
android:text="삭제"
app:layout_constraintLeft_toRightOf="#id/recycler_item_weight"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/recycler_item_weight_calculate" />
Related
I get the table and complete the title in the list on the start page, but the text not updated for some reason, what could be the problem?
I have a table:
#Entity(tableName = "Note_table")
class NoteModel (
#PrimaryKey(autoGenerate = true)
var id: Int = 0,
#ColumnInfo
var title: String = "",
#ColumnInfo
var description: String = ""
) : Serializable
I have RecyclerView:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardElevation="5dp"
app:cardCornerRadius="3dp"
android:layout_margin="1dp">
<TextView
android:id="#+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:text="title"
android:textColor="#color/blue"
android:textSize="20sp"
android:textStyle="bold" />
</androidx.cardview.widget.CardView>
and in the class NoteAdapte, i complete in the title (here - binding.itemTitle.text = listNote[position].title), but in the activity I get itemTitle.text = title:
class NoteAdapter: RecyclerView.Adapter<NoteAdapter.NoteViewHolder>() {
lateinit var binding: ItemLayoutBinding
var listNote = emptyList<NoteModel>()
class NoteViewHolder(view: View): RecyclerView.ViewHolder(view) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
binding = ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
return NoteViewHolder(view)
}
override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
binding.itemTitle.text = listNote[position].title
}
override fun getItemCount(): Int {
return listNote.size
}
#SuppressLint("NotifyDataSetChanged")
fun setList(list: List<NoteModel>){
listNote = list
notifyDataSetChanged()
}
override fun onViewAttachedToWindow(holder: NoteViewHolder) {
super.onViewAttachedToWindow(holder)
holder.itemView.setOnClickListener{
StartFragment.clickNote(listNote[holder.adapterPosition])
}
}
override fun onViewDetachedFromWindow(holder: NoteViewHolder) {
holder.itemView.setOnClickListener(null)
}
}
link to Git: https://github.com/Avdors/RoomLesson.git
enter image description here
You are suppose to have a ItemLayoutBinding per item in your Adapter.
Here you are not.
First change the declaration of the NoteViewHolder class.
class NoteViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding: ItemLayoutBinding
init {
binding = ItemLayoutBinding.bind(view)
}
}
The onCreateViewHolder method become :
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
return NoteViewHolder(view)
}
And the onBindViewHolder become:
override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
holder.binding.itemTitle.text = listNote[position].title
}
I don’t understand why the list is not filled with the help of a custom adapter. Only the last element from the array gets into textView (textHeroView). And it turns out that the ListView does not go as a list, but simply with one item from the array. I tried to put it on a separate list, to no avail. Can you please tell me what I made a mistake?
HeroesAdapter
class HeroesAdapter(context: Context, heroes: List<TestHero>): BaseAdapter() {
private val context = context
private val heroes = heroes
override fun getCount(): Int {
return heroes.count()
}
override fun getItem(position: Int): Any {
return heroes[position]
}
override fun getItemId(position: Int): Long {
return 0
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
// categoryView = LayoutInflater.from(context).inflate(R.layout.activity_heroes, null)
val listheroView = LayoutInflater.from(context).inflate(R.layout.list_hero_view, parent, false)
// val categoryImage: ImageView = categoryView.findViewById(R.id.heroesImageView)
val heroText: TextView = listheroView.findViewById(R.id.textHeroView)
val category = heroes[position]
// heroText.text = category.legends.all.keys.first()
for((key) in category.legends.all){
Log.d("HeroesActivity", key)
heroText.text = key
}
return listheroView
}
}
list_hero_view
<?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"
>
<ImageView
android:id="#+id/heroesImageView"
android:layout_width="426dp"
android:layout_height="180dp"
android:layout_marginTop="24dp"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.533"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="#mipmap/wraith_apex_legends" />
<TextView
android:id="#+id/textHeroView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Wraith"
android:textColor="#android:color/darker_gray"
android:textSize="54sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="#+id/heroesImageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.12"
app:layout_constraintStart_toStartOf="#+id/heroesImageView"
app:layout_constraintTop_toTopOf="#+id/heroesImageView"
app:layout_constraintVertical_bias="0.04000002" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_heroes
<?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=".HeroesActivity">
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="24dp"
app:layout_constraintBottom_toTopOf="#+id/heroesListView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#mipmap/ic_launcher_round" />
<ListView
android:id="#+id/heroesListView"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginStart="1dp"
android:layout_marginTop="100dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textNickname"
android:layout_width="251dp"
android:layout_height="29dp"
android:layout_marginStart="40dp"
android:layout_marginEnd="279dp"
android:layout_marginBottom="60dp"
android:text="Nickname"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="#+id/heroesListView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.145"
app:layout_constraintStart_toEndOf="#+id/imageView2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.272" />
<TextView
android:id="#+id/textLvl"
android:layout_width="111dp"
android:layout_height="19dp"
android:layout_marginEnd="28dp"
android:layout_marginBottom="42dp"
android:text="Lvl"
app:layout_constraintBottom_toTopOf="#+id/heroesListView"
app:layout_constraintEnd_toEndOf="#+id/textNickname"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/textNickname"
app:layout_constraintTop_toBottomOf="#+id/textNickname"
app:layout_constraintVertical_bias="0.562" />
</androidx.constraintlayout.widget.ConstraintLayout>
HeroesActivity
class HeroesActivity : AppCompatActivity() {
lateinit var heroesAdapt : HeroesAdapter
val listHero = ArrayList<TestHero>()
private val TAG = "HeroesActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_heroes)
getCurrentData()
val lisView : ListView = findViewById(R.id.heroesListView)
heroesAdapt = HeroesAdapter(this, listHero)
lisView.adapter = heroesAdapt
//heroesListView.adapter = heroesAdapt
// heroesAdapt = HeroesAdapter(this, arrayListOf("a","b","c","d","e","f"));
// lisView.adapter = heroesAdapt
}
private fun getCurrentData() {
val api = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiRequest::class.java)
GlobalScope.launch(Dispatchers.IO) {
val response = api.herList().awaitResponse()
if (response.isSuccessful) {
val data = response.body()!!
Log.d(TAG, data.toString())
withContext(Dispatchers.Main){
// adapter.add(data.global.name)
// adapt.add(data.global.platform)
listHero.add(data)
heroesAdapt.notifyDataSetChanged()
textNickname.text = "${data.global.name} (${data.global.rank.rankDiv} divisions)"
textLvl.text = "Level: ${data.global.level.toString()}"
when(data.global.rank.rankName){
"Silver" -> textNickname.setTextColor(Color.parseColor("#7A7A79"))
"Gold" -> textNickname.setTextColor(Color.parseColor("#E6D600"))
"Platinum" -> textNickname.setTextColor(Color.parseColor("#36BBCE"))
}
}
}
}
}
}
I think the problem is in this piece of code
for((key) in category.legends.all){
Log.d("HeroesActivity", key)
heroText.text = key
}
And logs screen
TestHero.kt
data class TestHero (#SerializedName("global") val global: PlayerInf,
#SerializedName("legends")val legends: AllLegends)
data class PlayerInf (val name: String, val uid: Long, val avatar: String, val platform: String,
val level: Int, val toNextLevelPercent: Int, val internalUpdateCount: Int, val bans: BanInf, val rank: RankInf)
data class BanInf (val isActive: Boolean, val remainingSeconds: Int)
data class RankInf (val rankScore: Int, val rankName: String, val rankDiv: Int, val rankImg: String)
data class AllLegends (#SerializedName("all") val all: Map<String, LegendWrapper> = emptyMap())
data class LegendWrapper(
val data: List<PlayerPerformance>? = emptyList()
)
data class PlayerPerformance(val name: String, val value: Int, val key: String)
To the adapter, it's one item for one view. Your backing List has only one item. Your for loop inside getView() is iterating some collection inside that single item, and setting the value of the same TextView over and over until it gets to the last one.
Since the backing type of your adapter is TestHero, your list view can only show one line item per instance of TestHero. You only have one instance of TestHero.
Based on what you're showing, you should make the backing type of your adapter whatever the type of the list TestHero.legends.all is. In your coroutine, you can pull that list out of your TestHero and pass it to your Adapter. You'll need to make the backing list property mutable.
And like I said in the comments, don't use mutable lists for this. You should start with an empty list.
For example, if the type of this list is Legend, your adapter should look something like:
class HeroesAdapter(): BaseAdapter() {
var heroes: List<Legend> = emptyList()
override fun getCount(): Int = heroes.size
override fun getItem(position: Int): = heroes[position]
override fun getItemId(position: Int) = position
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = convertView ?: LayoutInflater.from(parent.context).inflate(R.layout.list_hero_view, parent, false)
val heroText: TextView = view.findViewById(R.id.textHeroView)
val hero = heroes[position]
heroText.text = hero.keys.first()
return view
}
}
And in your Activity, get rid of the listHero property. In your coroutine, after you get your data, do
heroesAdapt.apply {
heroes = data.legends.all
notifyDataSetChanged()
}
Also, consider switching to RecyclerView. ListView is kind of obsolete and I keep expecting them to deprecate it because they have only worked on improving RecyclerView the past several years.
in your list_hero_view.xml, change the height from match parent to wrap content. Thanks me later :-P
I don't see any issue in your code,
try this :
Setting adapter :
binding.heroesListView.adapter = HeroesAdapter(applicationContext, arrayListOf("a","b","c","d","e","f"));
Adapter :
package com.example.stackoverflow
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
class HeroesAdapter(context: Context, heroes: List<String>): BaseAdapter() {
private val context = context
private val heroes = heroes
override fun getCount(): Int {
return heroes.count()
}
override fun getItem(position: Int): Any {
return heroes[position]
}
override fun getItemId(position: Int): Long {
return 0
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
// categoryView = LayoutInflater.from(context).inflate(R.layout.activity_heroes, null)
val listheroView = LayoutInflater.from(context).inflate(R.layout.item_hero, parent, false)
// val categoryImage: ImageView = categoryView.findViewById(R.id.heroesImageView)
val heroText: TextView = listheroView.findViewById(R.id.textHeroView)
val category = heroes[position]
heroText.text = category
return listheroView
}
}
I am relatively new in kotlin and I would like to know how I can display items by sections, like this: showing data in sections . I have two services, one returns the list of section names and the other returns the items for each section.
So far I did the following, the view is like this:
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools">
<TextView
android:id="#+id/header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="header" />
<androidx.appcompat.widget.SwitchCompat
android:id="#+id/header_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list_productos_seccion"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="#+id/header_switch"
app:layout_constraintStart_toStartOf="#+id/header_title"
app:layout_constraintTop_toBottomOf="#+id/header_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
and in my outer adapter I did the following, where I pass a list of sections to the adapter and for each one I consult the service to obtain items and display it:
class SeccionesAdapter(
var seccionClickAdapter: SeccionClickAdapter,
private val context: Context,
var fragment: Fragment,
var productoViewModel: ProductoViewModel,
var vm: ClientActivityViewModel
): RecyclerView.Adapter<SeccionesAdapter.MyViewHolder>() {
interface SeccionClickAdapter{
fun onSeccionClick(producto: ProductoQryDTO)
}
var dataList = emptyList<SeccionQryDTO>()
var productosLista = ArrayList<ProductoQryDTO>()
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun setData(seccionDTO: SeccionQryDTO) {
itemView.header_title.text = seccionDTO.nombre
itemView.header_switch.isChecked = seccionDTO.isSelected?: true
itemView.list_productos_seccion.layoutManager = LinearLayoutManager(context)
if (itemView.header_switch.isChecked) {
itemView.list_productos_seccion.visibility = View.VISIBLE
dataFromServer(seccionDTO.id, itemView)
}
itemView.header_switch.setOnCheckedChangeListener { _, isChecked -> visible(isChecked, seccionDTO.id) }
}
fun visible(isChecked: Boolean, idSeccionDTO: Int) {
if (isChecked) {
itemView.list_productos_seccion.visibility = View.VISIBLE
dataFromServer(idSeccionDTO, itemView)
} else {
itemView.list_productos_seccion.visibility = View.GONE
}
}
}
fun dataFromServer(idSeccionDTO: Int, itemView: View) {
productosLista.clear()
productoViewModel.getItems(
idSeccionDTO,
{
fragment.activity?.runOnUiThread {
productosLista.clear()
productosLista.addAll(it.data!!)
itemView.list_productos_seccion.adapter = ProductoxSeccionAdapter(context, productosLista, seccionClickAdapter)
}
}, {
Log.e("Error", "", it)
}
)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_header_model, parent, false))
}
override fun getItemCount(): Int {
return dataList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.setData(dataList[position]!!)
}
fun setSecciones(seccionesList : List<SeccionQryDTO>) {
this.dataList = seccionesList
notifyDataSetChanged()
}
}
The problem is that when the application is loaded, sometimes the amount of items that should be for each section is not shown, and when I scroll it begins to make calls to the service, also the elements disappear and it remains blank as shown in this image
blank space in sections.
Could you help me please? I don't know how I could handle this situation or if I should implement it in some other way
EDIT
This is my inner adapter: ProductoxSeccionAdapter
class ProductoxSeccionAdapter (
private val context: Context,
var listProductos: List<ProductoQryDTO>?,
var seccionClickAdapter: SeccionesAdapter.SeccionClickAdapter
) : RecyclerView.Adapter<ProductoxSeccionAdapter.MyViewHolder>() {
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun setData(producto: ProductoQryDTO) {
itemView.nombreProductoLista.text = producto.nombre
itemView.descProductoLista.text = producto.detalle
itemView.precioProductoLista.text = producto.simboloMoneda + producto.precio
itemView.setOnClickListener { seccionClickAdapter.onSeccionClick(producto) }
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_producto_cliente_lista, parent, false))
}
override fun getItemCount(): Int {
return listProductos!!.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.setData(listProductos!![position])
}
}
In my android app Api 28 with Kotlin, I create an Interface "listOfCountry.xml", an editText for search and a recycler view that contains all the list of country as the following code:
<EditText
android:id="#+id/search"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:padding="5dp"
android:layout_weight="1"
android:background="#android:color/transparent"
android:fontFamily="#font/cairo"
android:hint="Search..."
android:imeOptions="actionSearch"
android:maxLines="1"
android:singleLine="true"
android:textSize="14sp"/>
<TextView
android:id="#+id/cancelSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/cairo"
android:layout_marginTop="15dp"
android:layout_marginStart="20dp"
android:text="#string/cancel_msg"
android:textSize="14sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerViewGovernmentOrSectionList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/lyt_search" />
I want to get a country from the list with the search filter, the following code is the description of my adapter :
class CountryItemAdapter(var countries: Array<AddressesData>, var mListener: OnItemClickListener) : RecyclerView.Adapter<CountryItemAdapter.ViewHolder>()
, Filterable {
private var selectedPos = -1
var searchableList: MutableList<AddressesData> = arrayListOf()
private var onNothingFound: (() -> Unit)? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_country, parent, false)
return ViewHolder(view)
}
override fun getItemCount() = countries.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item: AddressesData = countries[position]
holder.tickImage.visibility = (if (selectedPos == position) View.VISIBLE else View.GONE)
holder.country.text = item.englishName.toString()
holder.itemView.setOnClickListener {
selectedPos = position
mListener.onItemClick(holder.itemView, item)
notifyDataSetChanged()
}
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val country: TextView = itemView.counrty
val tickImage: ImageView = itemView.tickGovernment
}
interface OnItemClickListener {
fun onItemClick(view: View, viewModel: AddressesData)
}
override fun getFilter(): Filter {
return object : Filter() {
private val filterResults = FilterResults()
override fun performFiltering(constraint: CharSequence?): FilterResults {
searchableList.clear()
if (constraint.isNullOrBlank()) {
searchableList.addAll(countries)
} else {
val filterPattern = constraint.toString().toLowerCase().trim { it <= ' ' }
for (item in 0..countries.size) {
if (countries[item].englishName!!.toLowerCase().contains(filterPattern)) {
searchableList.add(countries[item])
}
}}
return filterResults.also {
it.values = searchableList
}
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
if (searchableList.isNullOrEmpty())
onNothingFound?.invoke()
notifyDataSetChanged()
}
and I add the following code in my activity :
search.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
adapter.filter.filter(charSequence.toString())
}
override fun afterTextChanged(editable: Editable) {}
})
The filter didn't work, I would like to know where's the problem in my code and How can I correct it to make the filter work ?
I think you lost getItemCount method in your adapter, it must return actual size of items in adapter.
Its late but may it it will help someone,
You are filtering data in searchableList list but you have applied countries list to adapter.
Change accordingly it will work.
I have implemented a recyclerview within recyclerview. Here is my code
activity_main
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/rv_activity_main"
app:layoutManager="android.support.v7.widget.GridLayoutManager"
app:spanCount="2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
MainActivity
class MainActivity : AppCompatActivity() {
private var graduationList = ArrayList<Graduation>()
private var yearList = ArrayList<YearList>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initList()
rv_activity_main.adapter = MainAdapter(graduationList)
}
private fun initList(){
graduationList.clear()
yearList.clear()
yearList.add(YearList("2011"))
yearList.add(YearList("2012"))
yearList.add(YearList("2013"))
yearList.add(YearList("2014"))
yearList.add(YearList("2015"))
yearList.add(YearList("2016"))
yearList.add(YearList("2017"))
yearList.add(YearList("2018"))
yearList.add(YearList("2019"))
graduationList.add(Graduation("UG",yearList))
graduationList.add(Graduation("PG",yearList))
}
}
Graduation Pojo Class
data class Graduation(
var name: String,
var yearList: ArrayList<YearList>
)
YearList Pojo Class
data class YearList(var yearName: String)
MainAdapter
class MainAdapter(private var graduationList: ArrayList<Graduation>): RecyclerView.Adapter<MainAdapter.MainViewHolder>(){
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): MainViewHolder {
val itemView = LayoutInflater.from(p0.context).inflate(R.layout.cell_main_adapter,p0,false)
return MainViewHolder(itemView)
}
override fun getItemCount(): Int {
return graduationList.size
}
override fun onBindViewHolder(p0: MainViewHolder, p1: Int) {
p0.graduationTextView.text = graduationList[p1].name
p0.graduationRecyclerView.adapter = SecondAdapter(graduationList[p1].yearList)
}
inner class MainViewHolder(view: View): RecyclerView.ViewHolder(view){
var graduationTextView: TextView = view.findViewById(R.id.tv_cell_main_adapter)
var graduationRecyclerView: RecyclerView = view.findViewById(R.id.rv_cell_main_adapter)
}
}
SecondAdapter
class SecondAdapter(private var yearList: ArrayList<YearList>): RecyclerView.Adapter<SecondAdapter.SecondViewHolder>(){
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): SecondViewHolder {
val itemView = LayoutInflater.from(p0.context).inflate(R.layout.cell_second_adapter,p0,false)
return SecondViewHolder(itemView)
}
override fun getItemCount(): Int {
return yearList.size
}
override fun onBindViewHolder(p0: SecondViewHolder, p1: Int) {
p0.yearTextView.text = yearList[p1].yearName
p0.itemView.setOnClickListener {
Log.i("Pritish",yearList[p1].yearName+"\n")
}
}
inner class SecondViewHolder(view: View): RecyclerView.ViewHolder(view){
var yearTextView: TextView = view.findViewById(R.id.tv_cell_year_title)
}
}
ItemClick for MainAdapter should not be clickable so I have not added any itemClick for it. Suppose user clicks a particular year I know which year the user selected but my question is, how to know when a year is clicked whether it's from UG or PG without implementing a itemclick listener for MainAdapter?
Try this way,
Pass Graduation object in SecondAdapter constuctor from MainAdapter like below.
p0.graduationRecyclerView.adapter = SecondAdapter(graduationList[p1])
Second Adapter
class SecondAdapter(private var graduation: Graduation): RecyclerView.Adapter<SecondAdapter.SecondViewHolder>(){
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): SecondViewHolder {
val itemView = LayoutInflater.from(p0.context).inflate(R.layout.cell_second_adapter,p0,false)
return SecondViewHolder(itemView)
}
override fun getItemCount(): Int {
return graduation.yearList.size
}
override fun onBindViewHolder(p0: SecondViewHolder, p1: Int) {
p0.yearTextView.text = graduation.yearList[p1].yearName
p0.itemView.setOnClickListener {
Log.i("Pritish",graduation.yearList[p1].yearName+" "+graduation.name+"\n")
}
}
inner class SecondViewHolder(view: View): RecyclerView.ViewHolder(view){
var yearTextView: TextView = view.findViewById(R.id.tv_cell_year_title)
}
}