So I created a RecyclerView to generate beverage items and for some reason my recycler veiw keeps on repeating the first item.
I tried using
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
while using
holder.itemView.text_view1.text = user.name
holder.itemView.text_view2.text = user.name
holder.itemView.text_View3.text = user.name
and the the results are the same.
What's causing the repetition?
BeverageAdapter.kt
class BeverageAdapter(val List:ArrayList<Beverage>)
RecyclerView.Adapter<BeverageAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textViewName2 = itemView.findViewById(R.id.text_view1) as TextView
val texViewName3 = itemView.findViewById(R.id.text_view2) as TextView
val textViewHello = itemView.findViewById(R.id.text_View3) as TextView
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_activity, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return List.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val user: Beverage = List[position]
holder.textViewName2.text = user.name
holder.texViewName3.text = user.name
holder.textViewHello.text = user.name
}
}
Beverage.kt
data class Beverage(val name: String)
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.item_recycler_view)
recyclerView.setLayoutManager(LinearLayoutManager(this))
val users = ArrayList<Beverage> ()
users.add(Beverage("Coke"))
users.add(Beverage("Gingerale"))
users.add(Beverage("Rootbeer"))
val adapter = BeverageAdapter(users)
recyclerView.adapter = adapter
}
}
Don't use 3 different TextView .
Just use single TextView and set it in Adapter.
RecyclerView.Adapter<BeverageAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textViewName1 = itemView.findViewById(R.id.text_view1) as TextView
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_activity, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return List.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val user: Beverage = List[position]
holder.textViewName1.text = user.name
}
}
In RecyclerView basically you create one view and it repeats as many as data is there.
Related
i have a problem the postion value is lost when sending it to viewmodel
class itemAdapter_Fruit (private val context:fruit , val dataset:List<FruitsType>):RecyclerView.Adapter<itemAdapter_Fruit.ViewHolder>() {
class ViewHolder (view: View):RecyclerView.ViewHolder(view){
val fruitImage:ImageView = view.findViewById(R.id.fruit_image)
val fruittext:TextView = view.findViewById(R.id.Fruit_name_text)
init {
view.setOnClickListener{
val position =adapterPosition
datamodel().setpos(position)
view.findNavController().navigate(R.id.action_fruit2_to_clicked_Item)
}
}
}
override fun onCreateViewHolder (parent: ViewGroup, viewType: Int): itemAdapter_Fruit.ViewHolder {
val adapterlayout = LayoutInflater.from(parent.context).inflate(R.layout.fruits_list,parent,false)
return ViewHolder(adapterlayout)
}
override fun onBindViewHolder(holder: itemAdapter_Fruit.ViewHolder, position: Int) {
val item = dataset[position]
holder.fruitImage.setImageResource(item.ImageFruitId)
holder.fruittext.text=context.getText(item.FruitNameId)
}
override fun getItemCount(): Int {
return dataset.size
}
}
when i trying to send the data to viewmodel from recycler adapter it's lost
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 {
}}
This question already has answers here:
RecyclerView itemClickListener in Kotlin
(24 answers)
Closed 4 years ago.
I have a recycler view with 2 elements.I want to add 2 buttons in order to do different things(depends on which element of the recycler view.How is it possible to do that?My elements are textviews
SettingsActiv.kt
class SettingsActiv : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
val arrow_backBtn = findViewById(R.id.settingsToolbarBtn) as Button
arrow_backBtn.setOnClickListener{
startActivity(Intent(this, MainActivity::class.java))
}
val linearLayout = findViewById(R.id.constr) as LinearLayout
val recyclerView = RecyclerView(this)
val series = ArrayList<SeriesModel>()
recyclerView.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
series.add(SeriesModel("Unit of length","Meter"))
series.add(SeriesModel("Unit of temperature","Celcius"))
val adapter = MyAdapter(series)
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
recyclerView.adapter = adapter
linearLayout.addView(recyclerView,1)
}
MyAdapter.kt
class MyAdapter(private val seriesList: ArrayList<SeriesModel>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyAdapter.MyViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.activity_settings_child, parent, false)
return MyViewHolder(v)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.textViewName.text = seriesList[position].name
holder.textViewNameDesc.text = seriesList[position].desc
}
override fun getItemCount(): Int {
return seriesList.size
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textViewName = itemView.findViewById(R.id.name) as TextView
val textViewNameDesc = itemView.findViewById(R.id.desc) as TextView
}
}
Try this
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.textViewName.text = seriesList[position].name
holder.textViewNameDesc.text = seriesList[position].desc
holder.textViewName.setOnClickListener {
Toast.makeText(context,"clicked",Toast.LENGTH_SHORT).show()
}
}
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)
}
}