DJ2
DJ2

Reputation: 1741

handle button click inside recyclerView adapter

I have a recyclerView adapter named ArticleAdapter

import kotlinx.android.synthetic.main.articlerecycler_item.view.*


class ArticleAdapter(private val controller: IController) : RecyclerView.Adapter<ArticleViewHolder>() {

  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
      val view = LayoutInflater.from(parent.context).inflate(R.layout.articlerecycler_item, parent, false)
      return ArticleViewHolder(view)


  }
    // How implement a button click for `btnSave`
    /** Called when the user taps the Save button  */
     btnSave.setOnClickListener(){
        (R.layout.articlerecycler_item)
        AlertDialog.Builder(this)
                .setMessage("Article Saved.")
                .create()
                .show()
        // Do something in response to button click
    }

  override fun getItemCount(): Int {
      return controller.articles.size
  }

  override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {

      val article: Article = controller.articles[position]

      if(article.title.length > 100) {
        holder.itemView.titleTv.text = "${article.title.substring(0, 99)}..."
      } else {
        holder.itemView.titleTv.text = article.title
      }

      holder.itemView.authorTv.text = article.author
  }

}
class ArticleViewHolder(view: View?) : RecyclerView.ViewHolder(view)

Then in my recyclerView layout I have a button

<Button
    android:id="@+id/btnSave"
    android:layout_width="70dp"
    android:layout_height="40dp"
    android:onClick="btnSave"
    android:text="@string/save"
    android:textAlignment="center" />

Do I handle the event inside onBindViewHolder? I'm not sure how to implement the listener within my recyclerView adapter

Upvotes: 3

Views: 7725

Answers (3)

Alexander
Alexander

Reputation: 551

I suppose you should add an extension lister. Here's https://dzone.com/articles/click-listener-for-recyclerview-adapter. Also, you must add the custom listener for the save button.

override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {

  val article: Article = controller.articles[position]

  if(article.title.length > 100) {
    holder.itemView.titleTv.text = "${article.title.substring(0, 99)}..."
  } else {
    holder.itemView.titleTv.text = article.title
  }

  holder.itemView.authorTv.text = article.author
  

  *holder.btnSave.setOnClickListener(){_ ->
    **yourCustomListener**.OnClick(data/position) }*
}

Upvotes: 2

DawidJ
DawidJ

Reputation: 1265

You have to handle it in onBindViewHolder() but logic which is responsible for creating and showing AlertDialog shouldn't be located in RecyclerView. You need to create an interface, which will be responsible for passing onClick() event information from your adapter to activity/fragment, and there you should show AlertDialog.

class ArticleAdapter(private val controller: IController) : RecyclerView.Adapter<ArticleViewHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
    val view = LayoutInflater.from(parent.context).inflate(R.layout.articlerecycler_item, parent, false)
    return ArticleViewHolder(view)
}

override fun getItemCount(): Int {
    return controller.articles.size
}

override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
    val article: Article = controller.articles[position]

    if(article.title.length > 100) {
        holder.itemView.titleTv.text = "${article.title.substring(0, 99)}..."
    } else {
        holder.itemView.titleTv.text = article.title
    }

    btnSave.setOnClickListener {
        listener?.onSaveButtonClick()
    }

    holder.itemView.authorTv.text = article.author
}

private var listener: OnClickListener? = null

fun setListener(listener: OnClickListener) {
    this.listener = listener
}

}

interface OnClickListener {
    fun onSaveButtonClick()
}

class ArticleViewHolder(view: View?) : RecyclerView.ViewHolder(view)

Now pass the instance of OnClickListener from your activity to your adapter by setListener() method.

Upvotes: 1

Mosius
Mosius

Reputation: 1682

A good solution to handle the items click of an adapter is to pass them to the activity or fragment which has created them.

With kotlin you can use function definition instead of an interface for this simple work, so inside your adapter class add a var of a function type:

private var listener: ((item: DataClass) -> Unit)? = null

fun setOnItemClickListener(listener: (item: DataClass) -> Unit) {
    this.listener = listener
}

And inside the ViewHolder class set the listener, something like below:

class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    init {
        itemView.btn_save.setOnClickListener { listener?.invoke(data[adapterPosition]) }
    }

    // ...
}

Finally inside your activity or fragment you can easily access the items by adding a new listener:

adapter.setOnItemClickListener { it -> TODO() }

Notice that setting listeners inside ViewHolder constructor(init) is more efficient as it is not necessary to set a listener for every data binding.

Upvotes: 4

Related Questions