0

The view (test.xml):

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/files"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_marginStart="20dp"
    android:layout_marginEnd="20dp"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

And the item (item.xml):

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/text"
    android:textSize="20dp"
    android:layout_marginTop="20dp"
    android:layout_marginBottom="20dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

And the code:

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater.inflate(R.layout.test, container, false)

    class MyViewHolder(val view: View): RecyclerView.ViewHolder(view) {
        init {
            view.setOnClickListener {
                Log.d("path", files[adapterPosition].path)
                Log.d("pos", adapterPosition.toString())
            }
        }
    }

    val recyclerView = view.findViewById<RecyclerView>(R.id.files)
    recyclerView.addItemDecoration(DividerItemDecoration(recyclerView.context, DividerItemDecoration.VERTICAL))
    recyclerView.adapter = object: RecyclerView.Adapter<MyViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            val item = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
            return MyViewHolder(item)
        }

        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            holder.view.findViewById<TextView>(R.id.text).text = files[position].name
        }

        override fun getItemCount() = files.size
    }

    return view
}

files is a local array. The items are rendered, but the log message from the OnClickListener does't appear.

Zain
  • 37,492
  • 7
  • 60
  • 84
user1785730
  • 3,150
  • 4
  • 27
  • 50

4 Answers4

0

Try this sample code.

override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
    holder.view.findViewById<TextView>(R.id.text).text = files[position].name
    holder.view.setOnClickListener {
                Log.d("path", files[adapterPosition].path)
                Log.d("pos", adapterPosition.toString())
            }
}
Eyosiyas
  • 1,422
  • 1
  • 9
  • 25
  • `getAdapterPosition()` is from ViewHolder, not Adapter. – user1785730 Mar 17 '21 at 18:45
  • [This question](https://stackoverflow.com/questions/33845846/why-is-adding-an-onclicklistener-inside-onbindviewholder-of-a-recyclerview-adapt) indicates that setting the `OnClickListener` in `onBindViewHolder` is considered bad practice. – user1785730 Mar 17 '21 at 18:56
0

Use FastAdapter. https://github.com/mikepenz/FastAdapter

Click listener:

fastAdapter.onClickListener = { view, adapter, item, position ->
   // Handle click here
   false
}

Click listeners for views inside your item

fastAdapter.addEventHook(object : ClickEventHook<SimpleImageItem>() {
override fun onBind(viewHolder: RecyclerView.ViewHolder): View? {
    //return the views on which you want to bind this event
    return if (viewHolder is SimpleImageItem.ViewHolder) {
        viewHolder.viewWhichReactsOnClick
    } else {
    null
}
}

override fun onClick(v: View, position: Int, fastAdapter: FastAdapter<SimpleImageItem>, item: SimpleImageItem) {
    //react on the click event
}})
0

Your code should work fine, although I see the problem may be in the top & bottom margins you add to the item, clicking on these areas won't be detected by the clickListener as they are not a part of the root view, and the clicks will only be detected when you tap exactly on the TextView

You can solve this by using padding instead in your item:

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/text"
    android:textSize="20dp"
    android:paddingTop="20dp"
    android:paddingBottom="20dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
Zain
  • 37,492
  • 7
  • 60
  • 84
  • It is also possible that some transparent view is laid over the Recyclerview and blocks the clicks. Test it that is the case by adding some elevation to the view holder root layout. – Mieszko Koźma Mar 17 '21 at 15:54
  • @MieszkoKoźma possible reason, but I think OP shared only `RecyclerView` in `test.xml` so nothing intersecting – Zain Mar 17 '21 at 15:57
  • Using padding instead of margins didn't change anything. In any case, clicking directly on the text should've worked, if that were the problem. – user1785730 Mar 17 '21 at 18:38
0

The problem is that I named the variable for MyViewHolder "view", just like the first variable declared in onCreateView. Renaming the variable to "item" solved the problem:

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater.inflate(R.layout.file_explorer, container, false)

    class MyViewHolder(val item: View): RecyclerView.ViewHolder(item) {
        init {
            item.setOnClickListener {
                Log.d("path", files[adapterPosition].path)
                Log.d("pos", adapterPosition.toString())
                goto(files[adapterPosition].path)
            }
        }
    }

    val recyclerView = view.findViewById<RecyclerView>(R.id.files)
    recyclerView.addItemDecoration(DividerItemDecoration(recyclerView.context, DividerItemDecoration.VERTICAL))
    recyclerView.adapter = object: RecyclerView.Adapter<MyViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            val item = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
            return MyViewHolder(item)
        }

        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            holder.item.findViewById<TextView>(R.id.text).text = files[position].name
        }

        override fun getItemCount() = files.size
    }

    return view
}

The mechanics of this closure resolution elude me though and I've created a new question.

user1785730
  • 3,150
  • 4
  • 27
  • 50