0

I am trying to write a RecyclerView adapter class in Kotlin for android. I am trying to use the traditional way of creating a custom viewer class, for custom objects, and use a click listener in that. While I am able to do rest of the things like access the variables of inner class and show the RecyclerView, what I have not been able to do is add click listener to the var objects of inner class.

ie something like

 var convertView : View? = itemView

convertView.setOnClickListener(this)

Following is my complete code of adapter class

public open class TestAdapter(val items: MutableList<Any>, val context: Activity) : RecyclerView.Adapter<TestAdapter.CustomViewHolder>() {

public var mItem: MutableList<Any> = items
public var mActivity: Activity = context
protected var clickListener: ExampleInterface? = null
public interface ExampleInterface {

    fun click(pos: Int) {

    }
}


open public fun setListener(mInterFaceListener: ExampleInterface) {
    clickListener = mInterFaceListener
}

override fun onCreateViewHolder(p0: ViewGroup, p1: Int): CustomViewHolder {
    var parentLayout: View = LayoutInflater.from(mActivity).inflate(R.layout.custom_view, p0, false)
    return CustomViewHolder(parentLayout)

    //  return CustomViewHolder(LayoutInflater.from(mActivity).inflate(R.layout.custom_view, p0, false))
}

override fun getItemCount(): Int {
    return mItem.size
    TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun onBindViewHolder(p0: CustomViewHolder, p1: Int) {

    p0.dataView.text = mItem.get(p1).toString()

}

inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
    var convertView: View? = itemView
    var dataView: TextView = convertView!!.findViewById(R.id.data)

    var mposition = adapterPosition

    override fun onClick(p0: View?) {

        if (clickListener != null) {
            clickListener!!.click(mposition)
        }
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

}

}

So if you see these two lines in CustomView class

var convertView: View? = itemView
    var dataView: TextView = convertView!!.findViewById(R.id.data)

I cannot access these variables "convertView" and "dataView" so that I can set clicklistener to them. So how to achieve it ? Thanks :)

Mostafa Arian Nejad
  • 1,278
  • 1
  • 19
  • 32
Pritish
  • 1,284
  • 1
  • 19
  • 42

3 Answers3

1

I referred to this site

https://www.raywenderlich.com/367-android-recyclerview-tutorial-with-kotlin

Here I go to know my mistake , I need to use init in the class, there I am able to access it and initialize on click listener. Got it working

   init {
            convertView?.setOnClickListener(this)
        }

Though the above answer could be acceptable as well, as I am new to Kotlin I cannot say which one is the better option, but my requirement is satisfied with the above mentioned site.

Thank you :)

Pritish
  • 1,284
  • 1
  • 19
  • 42
0

you can access them in the onBindViewHolder using the p0 this way p0.dataView so there you can set listeners successfully

Ahmed Rajab
  • 603
  • 3
  • 10
  • 28
  • Yes but is it the proper way to do it ?? As bind holder is exclusively meant for setting data and it will keep on setting listener on every bind. Isn't it the reason we used to do that in custom view class traditionally in Java. – Pritish Oct 19 '18 at 05:26
  • N idea, I used it this way and it always works, never faced any problems @Pritish – Ahmed Rajab Oct 19 '18 at 05:29
  • So you write it separately for every variable like p0.dataView.setOnClickListener(View.OnClickListener { }) p0.dataView1.setOnClickListener(View.OnClickListener { }) – Pritish Oct 19 '18 at 05:32
  • no I do not ,it generates the listener to all (dataView)s, you may use the p1 to get the position of each one of the Views and customize adding the listeners @Pritish – Ahmed Rajab Oct 19 '18 at 05:35
0

In RecyclerView adapters, You could place the OnClickListeners in onCreateViewHolder in order to prevent them from being set each time onBindViewHolder is called (as onBindViewHolder is called multiple times when RecyclerView is scrolled). Use parentLayout in your onCreateViewHolder to access your views and set onClickListener to them. to determine current position in onCreateViewHolder you can do as below :

override fun onCreateViewHolder(p0: ViewGroup, p1: Int): CustomViewHolder {
    val parentLayout: View = LayoutInflater.from(mActivity).inflate(R.layout.custom_view, p0, false)
    
    val customViewHolder = CustomViewHolder(parentLayout)
    parentLayout.myExampleTextView.setOnClickListener {
        // Place onClick logic here.

        // If you need position, do as bellow :
        val adapterPosition = customViewHolder.adapterPosition
        if(adapterPosition != RecyclerView.NO_POSITION) {
            // Place your position dependent logic here
        }
    }
    
    return customViewHolder
}

UPDATE: I updated the code snippet above and added the RecyclerView.NO_POSITION (which is equal to -1) check. The reason for the position being returned as -1 is explained below.

From android docs:

The other set of position related methods are in the form of AdapterPosition. (e.g. getAdapterPosition(), findViewHolderForAdapterPosition(int)) You should use these methods when you need to work with up-to-date adapter positions even if they may not have been reflected to layout yet. For example, if you want to access the item in the adapter on a ViewHolder click, you should use getAdapterPosition(). Beware that these methods may not be able to calculate adapter positions if notifyDataSetChanged() has been called and new layout has not yet been calculated. For this reasons, you should carefully handle NO_POSITION or null results from these methods.

Community
  • 1
  • 1
Mostafa Arian Nejad
  • 1,278
  • 1
  • 19
  • 32
  • Hey can you please let me know where to write this code for postion var adapterPosition = viewHolder.adapterPosition Coz in onCreateViewHolder I am getting it as -1 – Pritish Oct 19 '18 at 06:05
  • Should this be in bindViewHolder and not in onCreateViewHolder ?? – Pritish Oct 19 '18 at 06:06
  • @Pritish I updated the answer, -1 being returned is explained and handled with an if statement, it should be handled to avoid any problem. As why to place `onClickListener` in `onCreateViewHolder`, take a look at this answer : https://stackoverflow.com/a/33845918/8551764 – Mostafa Arian Nejad Oct 19 '18 at 14:45
  • It's better to put that code into the CustomViewHolder's constructor, actually. – EpicPandaForce Oct 20 '18 at 16:53