如何在我的Recycler视图中为自定义ViewHolder实现OnClickListener?

时间:2017-10-09 07:28:52

标签: android android-recyclerview kotlin onclicklistener

我正在创建一个应用程序,它应该在recyclerview中显示蓝牙设备,我希望用户能够单击项目来执行操作。现在我只是试图在点击时出现一个祝酒词,但后来我想显示一个对话框,给出选择配对等等。但是我在使用onclicklistener时显然遗漏了一些东西。我正在尝试使用我的ViewHolder类: DeviceHolder 实现View.OnClickListener并将调用放在我的onClick覆盖中Toast.makeText()。然而,一切都没有发生。我相信我只是遗漏了一些小事,并希望能帮到找到问题。我也在kotlin这样做,我是新手,如果有可能更有效,kotlin类型的方式来做到这一点也会有所帮助。我在下面发布我的代码。提前谢谢。

class DeviceAdapter(val mContext : Context) : RecyclerView.Adapter<DeviceAdapter.DeviceHolder>(){

val mDevices = ArrayList<BluetoothDevice>()

interface OnClickListener{
    fun onClick(v: View)
}

fun updateItems(list: ArrayList<BluetoothDevice>){
    mDevices.clear()
    mDevices.addAll(list)
    Log.d(TAG, "updating items : $mDevices")
    notifyDataSetChanged()
}

fun ViewGroup.inflate(@LayoutRes res: Int, attachToRoot: Boolean = false): View{
    return LayoutInflater.from(mContext).inflate(res, this, attachToRoot)
}

override fun onBindViewHolder(holder: DeviceHolder, position: Int) {
    Log.d(TAG, "onBindViewHolder called!")
    holder.bindItems(mDevices.get(position))
}

override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): DeviceAdapter.DeviceHolder{
    Log.d(TAG, "onCreateViewHolder called!")
    val v = parent!!.inflate(R.layout.device_item, false)
    return DeviceHolder(v)
}

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

inner class DeviceHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {

    override fun onClick(v: View?) {
        Toast.makeText(mContext, "test", Toast.LENGTH_LONG).show()
    }

    val nameView = itemView.findViewById(R.id.nameView) as TextView
    val addrView = itemView.findViewById(R.id.addressView) as TextView

    fun bindItems(btDevice: BluetoothDevice) {
        Log.d(TAG, "holder created!")
        nameView.text = btDevice.name
        addrView.text = btDevice.address
        itemView.setOnClickListener { this }
    }

}

companion object {
    val TAG = "Device Adapter"
}
}

这是日志消息:

10-09 00:35:50.233 7581-7581/com.example.zemcd.toofxchange D/DiscoveryTask: device found!
10-09 00:35:51.795 7581-7581/com.example.zemcd.toofxchange D/DiscoveryTask: device found!
10-09 00:35:56.752 7581-7581/com.example.zemcd.toofxchange D/DiscoveryTask: device list : [**:B8:9A:39:1D:**, **:DF:BF:2A:F3:**]
10-09 00:35:56.752 7581-7581/com.example.zemcd.toofxchange D/Device Adapter: updating items : [**:B8:9A:39:1D:**, **:DF:BF:2A:F3:**]
10-09 00:35:56.752 7581-7581/com.example.zemcd.toofxchange D/DiscoveryTask: discovery finished
10-09 00:35:56.762 7581-7581/com.example.zemcd.toofxchange D/Device Adapter: onCreateViewHolder called!
10-09 00:35:56.774 7581-7581/com.example.zemcd.toofxchange D/Device Adapter: onBindViewHolder called!
10-09 00:35:56.774 7581-7581/com.example.zemcd.toofxchange D/Device Adapter: holder created!
10-09 00:35:56.783 7581-7581/com.example.zemcd.toofxchange D/Device Adapter: onCreateViewHolder called!
10-09 00:35:56.786 7581-7581/com.example.zemcd.toofxchange D/Device Adapter: onBindViewHolder called!
10-09 00:35:56.786 7581-7581/com.example.zemcd.toofxchange D/Device Adapter: holder created!

3 个答案:

答案 0 :(得分:2)

我设法通过取消OnClickListener的实现并仅使用此语句itemView.setOnClickListener { /* lamda here */ }来解决此问题。我不相信这种确切的语法在java中可用,但在kotlin中可用。这是我修改后的代码:

inner class DeviceHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    val nameView = itemView.findViewById(R.id.nameView) as TextView
    val addrView = itemView.findViewById(R.id.addressView) as TextView

    fun bindItems(btDevice: BluetoothDevice) {
        Log.d(TAG, "holder created!")
        nameView.text = btDevice.name
        addrView.text = btDevice.address
        itemView.setOnClickListener { Toast.makeText(it.context, "testing", Toast.LENGTH_SHORT).show() }
    }

}

通过在lambda中使用it关键字,我访问了itemView对象的上下文,而不是使用上面描述的原始mContext。我仍然不确定为什么我的旧方法不起作用,但这样做对我有用。

答案 1 :(得分:1)

这有效:

1将您自己的单击侦听器设置为适配器,并保留对它的引用:

private OnItemClickListener onItemClickListener;
// ...
public interface OnItemClickListener {
    // note: here you would need some params, for instance the view
    void onItemClick(View v);
}

public void setOnItemClickListener(OnItemClickListener l) {
    this.onItemClickListener = l;
}

2创建每个视图时,设置一个侦听器,一旦回调,将回调传递给1中的侦听器集:

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    ViewHolder vh = getViewHolder( /*...*/ );
    vh.setOnItemClickListener(new OnItemClickListener() {                
        if (onItemClickListener != null) {
            // each view holder calls the one listener set to the Adapter
            onItemClickListener.onItemClick(v);
        }
    }
}

3让你的观众听取onClick的(持有)视图,并让它转发电话:

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
// each view holder has a listener set to it   
private OnItemClickListener mListener;

public ViewHolder(View v) {        
    super(v);
    // ...
    // set the viewholder as a listener to the view's clicks
    v.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    // when view is clicked, simply forward the call
    if (mListener != null) {
        mListener.onItemClick(v);
    }
}

public void setOnItemClickListener(OnItemClickListener listener) {
    mListener = listener;
}

}

此时

4,适配器用户将拥有:

mAdapter = new MyAdapter(ctx);
mAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View v) {
        // the given view was clicked, do something with it
    }
});

答案 2 :(得分:0)

根据您的代码,您正在实施clicklistner,但尚未添加任何注册表单击listener.add clickListener nameViewAddrView

nameView.setOnClickListener(this);
addrView.setOnClickListener(this);