我们可以在回收器视图行项目上使用内置的setOnCliclListener代替自定义项目单击侦听器吗?

时间:2018-08-15 22:18:49

标签: android android-recyclerview kotlin onclicklistener onitemclicklistener

我已经看到了许多示例,这些示例为行项目提供单击功能(用于在回收器视图中选择行项目),但是所有这些示例都使用自定义单击侦听器类来实现。有什么方法可以实现这种点击功能?

2 个答案:

答案 0 :(得分:1)

检测RecyclerView项的单击非常简单。您需要做的就是定义一个接口(如果您不使用Kotlin,在这种情况下,您只需传入一个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
        }
    }
}

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
        }
    }
}

答案 1 :(得分:1)

如果使用Kotlin,则可以将方法作为构造函数参数或通过setter方法发送。对于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]) }
        }
    }
}

在适配器中,我们将函数用作名为listener的构造函数参数。然后单击项目视图,我们将使用所需类型调用该功能。

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

这就是为什么我沉迷于Kotlin的原因。在这种情况下,不需要接口回调。

已更新 如果您也想发送职位。

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

您必须使用两个参数来调用此函数。

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

现在我们可以看到有多个参数,因此it对于参数不起作用,我们必须为此lambda函数提供变量名称。

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