Override function onBindViewHolder is not overwriting when I add ViewHolder class inside it.
When I put viewHolder class outside it. it is not working.
Below in my code -
class data_custom_adapter(private val context: Context, private val datalist : ArrayList<Display_data>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.display_data_card, parent, false)
return CustomAdapter.ViewHolder(v)
}
//Issue occur here -- it is not overriding when I add ViewHolder class
override fun onBindViewHolder(holder: data_custom_adapter.ViewHolder, position: Int) {
holder.bindItems(context,datalist[position])
}
override fun getItemCount(): Int {
return datalist.size
}
//the class is holding the list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val datalist_data = itemView.findViewById(R.id.displayxmldata) as TextView
fun bindItems(context: Context, datashow : Display_data) {
datalist_data.text = datashow.appdata
}
}
}
Guys, please help to find out issue in this.
The ViewHolder must match the class that you indicate in the first line. so in
class data_custom_adapter(private val context: Context, private val datalist : ArrayList<Display_data>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
there's CustomAdapter.ViewHolder. Change this to your data_custom_adapter.ViewHolder and it should work. so like
class data_custom_adapter(private val context: Context, private val datalist : ArrayList<Display_data>) : RecyclerView.Adapter<data_custom_adapter.ViewHolder>() {
this needs to be also changed in the onCreateViewHolder function
I hope this will work.
class data_custom_adapter(
private val context: Context,
private val datalist : ArrayList<Display_data>) : RecyclerView.Adapter<data_custom_adapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.display_data_card, parent, false)
return data_custom_adapter.ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItems(context,datalist[position])
}
override fun getItemCount(): Int {
return datalist.size
}
//the class is holding the list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val datalist_data = itemView.findViewById(R.id.displayxmldata) as TextView
fun bindItems(context: Context, datashow : Display_data) {
datalist_data.text = datashow.appdata
}
}
}
Related
I'm trying to pass my binding variable for the adapter to the ViewHolder to assing values to the textviews in my adapter but the values are not assigned and the click listeners dont do anything.
Here's my adapter class:
class DoneAppointmentsAdapter(var context: DoneAppointmentsFragment, listener: ContentListener, var arrayList: List<Appointment>) :
RecyclerView.Adapter<DoneAppointmentsAdapter.ItemHolder>() {
private val listener: ContentListener = listener
private var binding: DoneAppointmentsAdapterBinding? = null
var activity = context
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ItemHolder {
val viewHolder = LayoutInflater.from(parent.context)
.inflate(R.layout.done_appointments_adapter, parent, false)
binding = DoneAppointmentsAdapterBinding.inflate(LayoutInflater.from(parent.context))
return ItemHolder(viewHolder,binding, parent.context)
}
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
holder.bind(arrayList, listener)
}
override fun getItemCount(): Int {
return arrayList.size
}
class ItemHolder(view: View, var binding: DoneAppointmentsAdapterBinding?, val context: Context) : RecyclerView.ViewHolder(view) {
fun bind(listOfData: List<Appointment>, listener: ContentListener) {
val dataListItem = listOfData[adapterPosition]
binding?.donePatientItemName?.text = "${dataListItem.patientName}"
binding?.donePatientItemTime?.text = "Some date"
binding?.donePatientItemPatientInfo?.setOnClickListener {
tempAppointmentId = dataListItem.id
listener.onPatientHistoryViewClicked(dataListItem.requestedBy)
}
binding?.donePatientItemReviewCase?.setOnClickListener {
amendPrescriptionWarning(dataListItem,context)
}
binding.donePatientItemViewCase.setOnClickListener {
startPreview(dataListItem)
}
}
}
}
You have messed up inside onCreateViewHolder . you have created view twice once with the LayoutInflater.from(parent.context) and once with DoneAppointmentsAdapterBinding.inflate . There should be only one in this case onlyDoneAppointmentsAdapterBinding .
class DoneAppointmentsAdapter(var context: DoneAppointmentsFragment, listener: ContentListener, var arrayList: List<Appointment>) :
RecyclerView.Adapter<DoneAppointmentsAdapter.ItemHolder>() {
private val listener: ContentListener = listener
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ItemHolder {
val binding = DoneAppointmentsAdapterBinding.inflate(LayoutInflater.from(parent.context))
return ItemHolder(binding)
}
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
holder.bind(arrayList, listener)
}
override fun getItemCount(): Int {
return arrayList.size
}
class ItemHolder (var binding: DoneAppointmentsAdapterBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(listOfData: List<Appointment>, listener: ContentListener) {
val dataListItem = listOfData[adapterPosition]
binding.donePatientItemName.text = "${dataListItem.patientName}"
binding.donePatientItemTime.text = "Some date"
binding.donePatientItemPatientInfo.setOnClickListener {
tempAppointmentId = dataListItem.id
listener.onPatientHistoryViewClicked(dataListItem.requestedBy)
}
binding.donePatientItemReviewCase.setOnClickListener {
amendPrescriptionWarning(dataListItem,binding.donePatientItemReviewCase.context)
}
binding.donePatientItemViewCase.setOnClickListener {
startPreview(dataListItem)
}
}
}
}
It should be like this . I have also removed extra useless arguments from ItemHolder .
To make it clear the problem with your code was RecyclerView.ViewHolder(view) you were passing view while you were doing all action and stuff on binding those holds are two different instances of View . Which should be fixed with above code.
I am new to Android & Kotlin. I want to click my row and intent it to other activity. That's why I tried to create an interface in my Adapter but it does not work. How can I create it?
My adapter code:
class NoteAdapter(private val titleTextArray: ArrayList<String>, private val imageArray: ArrayList<String>) : RecyclerView.Adapter<NoteAdapter.NoteHolder>() {
class NoteHolder (view: View) : RecyclerView.ViewHolder(view) {
var recyclerTitleText: TextView ?= null
var recyclerImageView: ImageView ?= null
init {
recyclerTitleText = view.findViewById(R.id.recyclerTitleText)
recyclerImageView = view.findViewById(R.id.recyclerImage)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.recycler_row, parent, false)
return NoteHolder(view)
}
override fun onBindViewHolder(holder: NoteHolder, position: Int) {
holder.recyclerTitleText?.text = titleTextArray[position]
Picasso.get().load(imageArray[position]).into(holder.recyclerImageView)
}
override fun getItemCount(): Int {
return titleTextArray.size
}
}
With Kotlin, you could to use a lambda (higher order function) to fetch the user clicks in the holder. For example, a base approach could be the next:
class YourAdapter(
private val listener: (String) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val yourDataList = emptyList<String>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.compound_checkbox_terms_layout, parent, false)
return YourViewHolder(view)
}
override fun getItemCount(): Int {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
private inner class YourViewHolder(view: View) : RecyclerView.ViewHolder(view) {
init {
if (adapterPosition != RecyclerView.NO_POSITION) {
val selectedData = yourDataList[adapterPosition]
listener.invoke(selectedData)
}
}
}
}
Pass the activity context to the adapter from Activity so it can launch intent
Activity Code :
mAdapter = new CustomAdapter(this, imageArray, ArrayList);
Adapter Code :
class NoteAdapter(private val titleTextArray: ArrayList, private val imageArray: ArrayList, private val context : Context) : RecyclerView.Adapter<NoteAdapter.NoteHolder>() {
class NoteHolder (view: View) : RecyclerView.ViewHolder(view) {
var recyclerTitleText: TextView?= null
var recyclerImageView : ImageView?= null
init {
recyclerTitleText = view.findViewById(R.id.recyclerTitleText)
recyclerImageView = view.findViewById(R.id.recyclerImage)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.recycler_row, parent, false)
return NoteHolder(view)
}
override fun onBindViewHolder(holder: NoteHolder, position: Int) {
holder.recyclerTitleText?.text = titleTextArray[position]
Picasso.get().load(imageArray[position]).into(holder.recyclerImageView)
holder.recyclerImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, NesneTani.class);
context.startActivity(intent);
}
});
}
override fun getItemCount(): Int {
return titleTextArray.size
}
}
Create an Interface to catch the click event. (position is optional)
interface OnItemClickListener {
fun onItemClick(position: Int)
}
add OnItemClickListener as a parameter in your Adapter class
class NoteAdapter(
private val titleTextArray: ArrayList<String>,
private val imageArray: ArrayList<String>,
private val listener: OnItemClickListener
) : RecyclerView.Adapter<NoteAdapter.NoteHolder>()
Then do below inside onBindViewHolder
override fun onBindViewHolder(holder: NoteHolder, position: Int) {
listener.onItemClick(position)
}
now inside your activity, implement the OnItemClickListener
class ActivityName implements OnItemClickListener{}
and while initiating adapter, do this
mAdapter = new CustomAdapter(this, imageArray, ArrayList);
Then inside the overridden method do what you want
override fun onItemClick(position: Int) {
//start the activity you want.
}
I have simple RecyclerViewAdapter class:
class TariffsCardAdapter(context: Context, tariffCardItems: List<ItemsItem?>?) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var context: Context? = null
private var tariffCardItems: ArrayList<ItemsItem?>? = null
init {
this.context=context
this.tariffCardItems=tariffCardItems as ArrayList<ItemsItem?>
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.layout_tariff_card_items, parent, false)
return TariffsCardAdapterViewHolder(view)
}
override fun getItemCount(): Int {
return tariffCardItems!!.size
}//getItemCount ends
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val viewHolder = holder as TariffsCardAdapterViewHolder
Log.e("posX","pos:::".plus(position))
}
private inner class TariffsCardAdapterViewHolder : RecyclerView.ViewHolder {
var text: TextView? = null
constructor(row: View) : super(row) {
text= row.findViewById(R.id.text) as TextView
}
}
}
Now lets suppose that my tariffCardItems: List<ItemsItem?> will have only 5 items in the list that I want to show.
The problem is that when the adapter gets instantiated that is for the first time the onBindViewHolder method is called twice.
So that the Log values prints as:
pos:::0
pos:::1
pos:::0
pos:::1
Which means that my recycler view position will be 1 in the end.
And the very first view will be created with list item at index 1 which is wrong and should be `0.
In other words, the very first child of the recycler view is created by 1 position value which is wrong.
What am I doing wrong?
It's simply because you are calling adapter 2 in code an recyclerview's bindviewholder should use to bind data not to call viewholder.
class TariffsCardAdapter(context: Context, tariffCardItems: List<ItemsItem?>?) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var context: Context? = null
private var tariffCardItems: ArrayList<ItemsItem?>? = null
init {
this.context=context
this.tariffCardItems=tariffCardItems as ArrayList<ItemsItem?>
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.layout_tariff_card_items, parent, false)
return TariffsCardAdapterViewHolder(view)
}
override fun getItemCount(): Int {
return tariffCardItems!!.size
}//getItemCount ends
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
//bind data
}
private inner class TariffsCardAdapterViewHolder : RecyclerView.ViewHolder {
var text: TextView? = null
constructor(row: View) : super(row) {
text= row.findViewById(R.id.text) as TextView
}
}
}
For example your adapter should be like this
class CustomAdapter(val userList: ArrayList<User>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
//this method is returning the view for each item in the list
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_layout, parent, false)
return ViewHolder(v)
}
//this method is binding the data on the list
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.bindItems(userList[position])
}
//this method is giving the size of the list
override fun getItemCount(): Int {
return userList.size
}
//the class is hodling the list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(user: User) {
val textViewName = itemView.findViewById(R.id.textViewUsername) as TextView
val textViewAddress = itemView.findViewById(R.id.textViewAddress) as TextView
textViewName.text = user.name
textViewAddress.text = user.address
}
}
}
This method from your code is calling twice
val viewHolder = holder as TariffsCardAdapterViewHolder
Log.e("posX","pos:::".plus(position))
I am trying to retrieve a testvar value from inner class Adapter to addtocart function but I am not getting the value. I am able to retrieve value inside Adapter class but not outside the class.
Code:
inner class MoviesAdapter : RecyclerView.Adapter<MoviesAdapter.MovieViewHolder>() {
private val movies: MutableList<Movie> = mutableListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieViewHolder {
return MovieViewHolder(layoutInflater.inflate(R.layout.item_movie_layout, parent, false))
}
override fun getItemCount(): Int {
return movies.size
}
override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
holder.bindModel(movies[position])
}
fun setMovies(data: List<Movie>) {
movies.addAll(data)
notifyDataSetChanged()
}
inner class MovieViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val movieGenreTxt : TextView = itemView.findViewById(R.id.movieGenre)
val movieYearTxt : TextView = itemView.findViewById(R.id.movieYear)
val movieAvatarImage : ImageView = itemView.findViewById(R.id.movieAvatar)
val movieDescription: TextView =itemView.findViewById(R.id.movieDescription)
fun bindModel(movie: Movie) {
// movieTitleTxt.text = movie.name
movieGenreTxt.text = movie.menu
movieYearTxt.text = movie.price
Picasso.get().load(movie.picture).into(movieAvatarImage)
movieDescription.text=movie.description
var movieName:String= movie.name!!
var testvar=movie.name.toString()
}
}
}
fun addtocart(view: View)
{
Toast.makeText(context,"Success on Click", Toast.LENGTH_SHORT).show()
print testvar
}
Think you are looking to put a button in the RecyclerView.
In that case setOnclicklistener within the
inner class MovieViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val addtocart = itemView.findViewById<Button>(R.id.viewprofile)
addtocart!!.setOnClickListener {
}}
I want to implement onClickListener on recyclerview item. Here is my CustomAdapter.kt Code.
package com.png.kotlinsample
/**
* Created by admin on 13-08-2017.
*/
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
/**
* Created by prashant on 6/19/2017.
*/
class CustomAdapter(val userList: ArrayList<User>, val listener: (User) -> Unit) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
//this method is returning the view for each item in the list
class MyAdapter(val userList: ArrayList<User>)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false)
return ViewHolder(v)
}
//this method is binding the data on the list
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.bindItems(userList[position],listener)
}
//this method is giving the size of the list
override fun getItemCount(): Int {
return userList.size
}
//the class is hodling the list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(user: User, listener: (User) -> Unit) = with(itemView) {
val textViewName = itemView.findViewById(R.id.textViewUsername) as TextView
val textViewAddress = itemView.findViewById(R.id.textViewAddress) as TextView
textViewName.text = user.name
textViewAddress.text = user.address
setOnClickListener { listener(user) }
}
}
}
I want the click listener callback from my activity.
class CustomAdapter(
val userList: List<User>,
val listener: (User) -> Unit
) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder = ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false))
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.bindItems(userList[position])
}
override fun getItemCount(): Int = userList.size
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textViewName: TextView = itemView.findViewById(R.id.textViewUsername)
private val textViewAddress: TextView = itemView.findViewById(R.id.textViewAddress)
fun bindItems(user: User) = with(itemView) {
textViewName.text = user.name
textViewAddress.text = user.address
setOnClickListener { listener(user) }
}
}
}
Then
val adapter = CustomAdapter(userList) { user ->
// do something with user on click
}
recyclerView.adapter = adapter
Ok let's do it in 3 steps
1- You define a interface with onClick method to be your callbacks
like this
interface UserClickCallbacks {
fun onUserClick(user: User)
}
2- Second in your adapter you add a click listener in the view holder with call the interface method like this
EDIT
class CustomAdapter(val userList: ArrayList<User>, private val userClickCallbacks: UserClickCallbacks) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
//this method is returning the view for each item in the list
class MyAdapter(val userList: ArrayList<User>)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false)
return ViewHolder(v)
}
//this method is binding the data on the list
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.textViewName.text = user.name
holder.textViewAddress.text = user.address
}
//this method is giving the size of the list
override fun getItemCount(): Int {
return userList.size
}
//the class is hodling the list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
init {
view.setOnClickListener(this)
}
val textViewName = itemView.findViewById(R.id.textViewUsername)
val textViewAddress = itemView.findViewById(R.id.textViewAddress)
override fun onClick(p0: View?) {
userClickCallbacks.onUserClick(userList[adapterPosition])
}
}
}
3- At your activity you implement the the UserClickCallbacks interface
and override the onUserClick() method like this
class UserActivity : AppCompatActivity(), UserClickCallbacks {
// your activity code
override fun onUserClick(user: User) {
// but the user click event logic here
// This triggered when user in tha adapter clicked
}
}
Don't forget to add inner to ViewHolder class or else you won't get access to listener object which is inside Adapter :
package com.niel.customview
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
/**
* Created by nileshdeokar on 12/03/2018.
*/
class MediaAdapter(private var mData: ArrayList<String>) : RecyclerView.Adapter<MediaAdapter.ViewHolder>() {
lateinit var listener: OnItemClickedListener
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent?.context)
.inflate(R.layout.row_media, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
val model = mData[position]
}
override fun getItemCount(): Int {
return mData.size
}
inner class ViewHolder : RecyclerView.ViewHolder, View.OnClickListener {
var imageViewSq: ImageView
constructor(itemView: View?) : super(itemView) {
imageViewSq = itemView?.findViewById(R.id.imgSq)!!
itemView.setOnClickListener(this)
}
override fun onClick(p0: View?) {
listener.onItemClick(adapterPosition)
}
}
fun setOnItemClickedListener(listener: OnItemClickedListener) {
this.listener = listener
}
interface OnItemClickedListener {
fun onItemClick(position: Int)
}
}