【问题标题】:how to implement OnClickListener for custom ViewHolder in my recycler view?如何在我的回收站视图中为自定义 ViewHolder 实现 OnClickListener?
【发布时间】:2017-10-09 07:28:51
【问题描述】:

我正在创建一个应用程序,该应用程序应该在回收站视图中显示蓝牙设备,并且我希望用户能够单击这些项目以执行操作。现在我只是试图在点击时出现一个祝酒词,但后来我想可能会显示一个对话框,给出配对的选择等。但是我在使用 onclicklistener 时显然遗漏了一些东西。我正在尝试让我的 ViewHolder 类:DeviceHolder 实现 View.OnClickListener 并将对 Toast.makeText() 的调用放在我的 onClick 覆盖内。但是,什么都没有发生。我确定我只是遗漏了一些小问题,希望能帮助您找到问题。我也在 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!

【问题讨论】:

  • 您在日志中看到了什么?既然你有所有这些不错的日志语句。
  • @Vucko 我发布了一个包含我的日志消息的编辑。
  • 您的项目视图是否可点击?检查xml。这一切似乎都是合法的。
  • @Vucko 我的 xml 应该包含什么才能使我的 itemview 可点击?我只有一个包含两个文本视图的线性布局。
  • 不确定,也许其他东西正在消耗点击事件。尝试在布局或其他东西上设置clickable="true"

标签: android android-recyclerview kotlin onclicklistener


【解决方案1】:

我设法通过消除 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。我仍然不确定为什么我的旧方法不起作用,但这确实对我有用。

【讨论】:

    【解决方案2】:

    这行得通:

    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 每个viewholder创建的时候,给它设置一个监听器,一旦回调,就将回调传给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 让你的viewholder监听(持有的)view 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
        }
    });
    

    【讨论】:

      【解决方案3】:

      根据您的代码,您正在实现 clicklistner,但尚未添加任何寄存器来单击侦听器。为 nameViewAddrView 添加 clickListener。

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

      【讨论】:

        猜你喜欢
        • 2021-10-01
        • 2015-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多