Can we make use of in built setOnCliclListener on recycler view row item instead of custom item click listener?

亡梦爱人 提交于 2020-01-16 11:25:14

问题


I have seen many examples for providing click functionality (for selecting row item in recycler view) to a row item, but all of them are using custom click listener class to achieve this. Is there any method to achieve this click functionality?


回答1:


Detecting click on a RecyclerView item is very easy. All you need to do is define an interface (if you're not using Kotlin, in which case you just pass in a lambda):

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private final Clicks clicks;

    public MyAdapter(Clicks clicks) {
        this.clicks = clicks;
    }

    private List<MyObject> items = Collections.emptyList();

    public void updateData(List<MyObject> items) {
        this.items = items;
        notifyDataSetChanged(); // TODO: use ListAdapter for diffing instead if you need animations
    }

    public interface Clicks {
        void onItemSelected(MyObject myObject, int position);
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        private MyObject myObject;    

        public MyViewHolder(View view) {
            super(view);
            // bind views
            view.setOnClickListener((v) -> {
                int adapterPosition = getAdapterPosition();
                if(adapterPosition >= 0) {
                    clicks.onItemSelected(myObject, adapterPosition);
                }
            });
        }

        public void bind(MyObject myObject) {
            this.myObject = myObject;
            // bind data to views
        }
    }
}

Same code in Kotlin:

class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter<MyViewHolder>() {
    private var items: List<MyObject> = Collections.emptyList()

    fun updateData(items: List<MyObject>) {
        this.items = items
        notifyDataSetChanged() // TODO: use ListAdapter for diffing instead if you need animations
    }

    inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) {
        private lateinit var myObject: MyObject

        init {
            // binds views
            myView.onClick {
                val adapterPosition = getAdapterPosition()
                if(adapterPosition >= 0) {
                    itemClicks.invoke(myObject, adapterPosition)
                }
            }
        }

        fun bind(myObject: MyObject) {
            this.myObject = myObject
            // bind data to views
        }
    }
}



回答2:


If you are using Kotlin then you can send method as constructor parameter or via setter method. You don't need to created any interface listener for this kind of situation in kotlin.

class ImageCategoryAdapter(val listener: (YourType) -> Unit) : RecyclerView.Adapter<ImageCategoryAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_poll_category, parent, false))
    }

    override fun getItemCount() = yourList.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // ...
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        // ...
        init {
            // this is the magic
            itemView.setOnClickListener { listener.invoke(yourList[adapterPosition]) }
        }
    }
}

In adapter we are taking function as constructor parameter named listener. and then on click of item view we are invoking that function with required type.

val adapter = ImageCategoryAdapter {
    // Your callback 
    // here it will be type of parameter which we are sending from adapter by invoking the function.
    processClickedItem(it)
}

This is why i am getting addicted to kotlin. No interface callback needed for this kind of situation.

Updated If you want to send the position also.

class ImageCategoryAdapter(val listener: (YourType, Int) -> Unit) : RecyclerView.Adapter<ImageCategoryAdapter.ViewHolder>() {
 ...
}

You have to invoke this function with two parameter.

itemView.setOnClickListener { listener.invoke(yourList[adapterPosition], adapterPosition) }

Now as we can see there are multiple parameter so it will not work for parameter, we have to provide the variable name for this lambda function.

val adapter = ImageCategoryAdapter { clickItem, position -> processClickedItem(clickItem, position)} 


来源:https://stackoverflow.com/questions/51867215/can-we-make-use-of-in-built-setonclicllistener-on-recycler-view-row-item-instead

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!