Kotlin 中的 RecyclerView itemClickListener [关闭]
Posted
技术标签:
【中文标题】Kotlin 中的 RecyclerView itemClickListener [关闭]【英文标题】:RecyclerView itemClickListener in Kotlin [closed] 【发布时间】:2015-06-08 02:47:02 【问题描述】:在拥有 3 年的 android 经验后,我正在使用 Kotlin 编写我的第一个应用程序。 只是对如何在 Kotlin 中使用带有 RecyclerView 的 itemClickListener 感到困惑。
我已经尝试过 trait (edit: now interface) 方法,非常类似于 Java
public class MainActivity : ActionBarActivity()
protected override fun onCreate(savedInstanceState: Bundle?)
// set content view etc go above this line
class itemClickListener : ItemClickListener
override fun onItemClick(view: View, position: Int)
Toast.makeText(this@MainActivity, "TEST: " + position, Toast.LENGTH_SHORT).show()
val adapter = DrawerAdapter(itemClickListener())
mRecyclerView.setAdapter(adapter)
trait ItemClickListener
fun onItemClick(view: View, position: Int)
这似乎很多余,所以我尝试了内部类方法:
inner class ItemClickListener
fun onItemClick(view: View, position: Int)
startActivityFromFragmentForResult<SelectExerciseActivity>(SELECT_EXERCISES)
然后像这样设置适配器的点击监听器:
val adapter = WorkoutsAdapter(ItemClickListener())
但我仍然对此不满意,因为我认为可能有更好、更清洁的方法。我试图从本质上实现这样的目标: RecyclerView onClick
有什么建议吗?
最终选择了批准答案的变体
在activity中定义函数:
val itemOnClick: (View, Int, Int) -> Unit = view, position, type ->
Log.d(TAG, "test")
像这样将函数本身传递给适配器:
class ExercisesAdapter(val itemClickListener: (View, Int, Int) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder
// other stuff up here
val vhExercise = ExerciseVH(view) // view holder
// on to the view holder through the extension function
vhExercise.onClick(itemClickListener)
在下面批准的答案中通过 Loop 扩展功能。
fun <T : RecyclerView.ViewHolder> T.onClick(event: (view: View, position: Int, type: Int) -> Unit): T
itemView.setOnClickListener
event.invoke(it, getAdapterPosition(), getItemViewType())
return this
【问题讨论】:
在你的activity中如何调用扩展函数onClick 您在 Adapter 的构造函数中设置了 itemClickListener(本例中为 itemOnClick)。 ViewHolder 调用它。事后看来,这仍然有效,我可能应该更多地使用它,哈哈。这些天,每次都继续制作手动 onClick 方法。 您也可以采用 Rx 或 LiveData 方法来避免使用回调来传递您的事件。 【参考方案1】:我的解决方案就像以前的解决方案与来自活动的超级干净调用的组合。
ContactAdapter:
class ContactAdapter @Inject constructor() : RecyclerView.Adapter<ContactAdapter.ViewHolder>()
var onItemClick: ((Contact) -> Unit)? = null
var contacts: List<Contact> = emptyList()
...
override fun onBindViewHolder(holder: ViewHolder, position: Int)
val contact = contacts[position]
holder.email.text = contact.email
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
val email: TextView = itemView.email
init
itemView.setOnClickListener
onItemClick?.invoke(contacts[adapterPosition])
联系活动:
override fun setupRecyclerAdapter()
recyclerView.adapter = contactAdapter
recyclerView.layoutManager = LinearLayoutManager(this)
contactAdapter.onItemClick = contact ->
// do something with your item
Log.d("TAG", contact.email)
【讨论】:
不错,我喜欢这个 我也是,它在我更新 UI 时解决了一个问题,非常感谢 记得清除 onDestroyView 的引用,因为这可能会泄漏。 谢谢,@denwehrle。我也喜欢 ios 中的这种风格。 这是什么override fun setupRecyclerAdapter
?它从哪里覆盖?【参考方案2】:
我有一点不同的方法。你可以为你的 ViewHolder 创建一个扩展
fun <T : RecyclerView.ViewHolder> T.listen(event: (position: Int, type: Int) -> Unit): T
itemView.setOnClickListener
event.invoke(getAdapterPosition(), getItemViewType())
return this
然后像这样在适配器中使用它
class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder>()
val items: MutableList<String> = arrayListOf()
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MyViewHolder?
val inflater = LayoutInflater.from(parent!!.getContext())
val view = inflater.inflate(R.layout.item_view, parent, false)
return MyViewHolder(view).listen pos, type ->
val item = items.get(pos)
//TODO do other stuff here
override fun onBindViewHolder(holder: MyViewHolder?, position: Int)
override fun getItemCount(): Int
return items.size()
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view)
我正在与我的同事一起在 library 上提供此类扩展。
【讨论】:
这在适配器中被调用。如何在 mainActivity 中使用 this 作为回调? @bpolat 你可以创建一个回调,例如 MyAdapter(private val itemClickedListener: (String) -> Unit),并在监听函数中用 itemClickedListener.invoke(item) 调用它。在你的活动中,你实例化适配器 = MyAdapter /*在这里处理你的 cb*/ 如何处理longOnClickListener? 通过这种方式onClick方法并不是每次都被调用。 我注意到如果在方法onCreateViewHolder
中添加OnClickListener
,那么有时它不起作用。所以我建议在方法onBindViewHolder
中添加OnClickListener
【参考方案3】:
如果有人在寻找更简洁的答案,我尝试了以下方法 - 这与 AfzalivE 的解决方案非常相似:
在我的适配器类中,我将clickListener
作为参数传递。在onBindViewHolder
上,我使用setOnClickListener
调用clickListener
并处理点击事件。
MyAdapter.kt:
class MyAdapter constructor(objects: ArrayList<MyObject>, val clickListener: (MyObject) -> Unit) : RecyclerView.Adapter<MyAdapter.Holder>()
private var mObjects : ArrayList<MyObject> = ArrayList<MyObject>()
init
mObjects = objects
override fun onBindViewHolder(holder: Holder?, position: Int)
var item : MyObject = objects[position]
// Calling the clickListener sent by the constructor
holder?.containerView?.setOnClickListener clickListener(item)
// More code (ViewHolder definitions and stuff)...
注意:我需要来自列表项的容器(根视图)的引用,在本例中为 containerView
然后我将我的对象作为参数传递,而无需再次在列表中搜索它并直接在我的Activity
类上处理它,在我设置适配器的那一刻:
MyActivity.kt:
myRecyclerView?.adapter = MyAdapter(mObjects)
Log.e("Activity", "Clicked on item $it.itemName")
更新
如果需要获取被点击项的位置,只需将其定义为回调中的参数,然后再将其发送回来。注意下面的val clickListener: (MyObject, Int) -> Unit
:
MyAdapter.kt
class MyAdapter constructor(objects: ArrayList<MyObject>, val clickListener: (MyObject, Int) -> Unit) : RecyclerView.Adapter<MyAdapter.Holder>()
// Rest of the code...
然后在onBindViewHolder()
上调用回调方法时传递位置:
override fun onBindViewHolder(holder: Holder?, position: Int)
var item : MyObject = objects[position]
// Calling the clickListener sent by the constructor
holder?.containerView?.setOnClickListener clickListener(item, position)
在 MyActivity.kt 上,您必须更改设置适配器的方式,以便获得位置。像这样:
myRecyclerView?.adapter = MyAdapter(mObjects) itemDto: MyObject, position: Int ->
Log.e("MyActivity", "Clicked on item $itemDto.someItemPropertyLikeName at position $position")
【讨论】:
@YLS 刚刚编辑了带有更新的帖子。在上面检查:) 我喜欢这种简单易懂的方式 我喜欢它!非常简洁的答案。 应该避免这种方法,因为点击监听器应该在创建持有人时设置一次。通过这样做,你会触发很多 setOnClickListeners 您可以使用ListAdapter
代替 RecyclerView.Adapter 并使用getItem(position)
检索当前项目而不是传递整个对象列表。【参考方案4】:
抱歉耽搁了,从this 链接得到了一个很棒的答案,它是用 Java 编写的。 做了一些作业并将其转换为 Kotlin..
现在它可以正常工作了。这是代码,
创建一个名为 RecyclerItemClickListenr 的类,
class RecyclerItemClickListenr(context: Context, recyclerView: RecyclerView, private val mListener: OnItemClickListener?) : RecyclerView.OnItemTouchListener
private val mGestureDetector: GestureDetector
interface OnItemClickListener
fun onItemClick(view: View, position: Int)
fun onItemLongClick(view: View?, position: Int)
init
mGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener()
override fun onSingleTapUp(e: MotionEvent): Boolean
return true
override fun onLongPress(e: MotionEvent)
val childView = recyclerView.findChildViewUnder(e.x, e.y)
if (childView != null && mListener != null)
mListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView))
)
override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean
val childView = view.findChildViewUnder(e.x, e.y)
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e))
mListener.onItemClick(childView, view.getChildAdapterPosition(childView))
return false
override fun onTouchEvent(view: RecyclerView, motionEvent: MotionEvent)
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean)
并从 Activity/Fragment 访问它
recyclerView.addOnItemTouchListener(RecyclerItemClickListenr(this, recyclerView, object : RecyclerItemClickListenr.OnItemClickListener
override fun onItemClick(view: View, position: Int)
//do your work here..
override fun onItemLongClick(view: View?, position: Int)
TODO("do nothing")
))
【讨论】:
当您可以在项目视图上设置点击侦听器时,为什么还需要手势检测器和触摸事件处理? @EpicPandaForce ,这种基于 Activity 的点击的点击监听方式,而不是在适配器中。 @Sam 感谢您的反馈。 这是一个了不起的人,你为我节省了一天的时间,而且也很有风格:) 这是个好人...【参考方案5】:在onBindViewHolder fun上添加ClickListener代码
override fun onBindViewHolder(holder: ViewHolder, position: Int)
holder.vieww.textView.setText(arr.get(position))
holder.vieww.setOnClickListener (holder.vieww.textView.setTextColor(Color.GREEN)) // click event
【讨论】:
最简单但最好的答案! 完美!感谢分享! 在使用这种方法时如何显示 Toast 或使用 Intent?它抛出一个错误 @RaheelKhan 您需要使用holder.itemView.context
获取上下文,然后您也可以使用toast 和intent。例如:Toast.makeText(holder.itemView.context, list[position].toString(), Toast.LENGTH_SHORT).show()
这种方法有什么缺点吗?在“位置”直接可用的地方设置监听器似乎是合乎逻辑的。【参考方案6】:
略有不同,基于 denwehrle
在 OnCreateView 内部的片段上使用
adapter.onItemClick = it ->
//do something
在适配器类中添加:
var onItemClick: ((Contact)->Unit) ?= null
...
inner class contactViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
val myItemView: TextView = itemView.findViewById(R.id.textView)
init
itemView.setOnClickListener
onItemClick?.invoke(contact[adapterPosition])
【讨论】:
@AfzalivE,为什么? @mithril_knight 因为它会导致父类泄漏。 ***.com/questions/31302341/…【参考方案7】:于 05 - 2019 年更新
我认为最优雅的解决方案是将这个责任交给 recyclerView 而不是查看甚至调整它。
为此我们需要:
1:创建 RecyclerItemClickListener 文件
class RecyclerItemClickListener(
private val mRecycler: RecyclerView,
private val clickListener: ((position: Int, view: View) -> Unit)? = null,
private val longClickListener: ((position: Int, view: View) -> Unit)? = null
) : RecyclerView.OnChildAttachStateChangeListener
override fun onChildViewDetachedFromWindow(view: View)
view.setOnClickListener(null)
view.setOnLongClickListener(null)
override fun onChildViewAttachedToWindow(view: View)
view.setOnClickListener v -> setOnChildAttachedToWindow(v)
private fun setOnChildAttachedToWindow(v: View?)
if (v != null)
val position = mRecycler.getChildLayoutPosition(v)
if (position >= 0)
clickListener?.invoke(position, v)
longClickListener?.invoke(position, v)
2:为 RecyclerView 创建/添加扩展:
import android.support.v7.widget.RecyclerView
import com.app.manager.internal.common.RecyclerItemClickListener
@JvmOverloads
fun RecyclerView.affectOnItemClicks(onClick: ((position: Int, view: View) -> Unit)? = null, onLongClick: ((position: Int, view: View) -> Unit)? = null)
this.addOnChildAttachStateChangeListener(RecyclerItemClickListener(this, onClick, onLongClick))
3:最后是使用(我想你使用 kotlinx)
import kotlinx.android.synthetic.main.your_layout_name.*
class FragmentName : Fragment()
override fun onViewCreated(view: View?, savedInstanceState: Bundle?)
recycler.affectOnItemClick position, view -> /*todo*/
【讨论】:
有人能详细说明为什么这是一个好的解决方案吗?我是 Android 开发新手,这对我来说似乎非常冗长和样板。 这是一个解决方案,但你的直觉是正确的——这里有太多的样板。虽然理解 kotlin 语法需要经过几次,但可以在这里找到一个不错的方法:antonioleiva.com/recyclerview-adapter-kotlin【参考方案8】:您不需要为 ViewHolder 或类似的东西编写扩展函数。 最佳实践;使用高阶函数
MainRecyclerAdapter
class MainRecyclerAdapter(val news: JSONArray, private val itemClickListener: (Int) -> Unit) : RecyclerView.Adapter<MainRecyclerAdapter.ViewHolder>()
只需添加一个高阶函数。像 itemClickListener 然后转到 ViewHolder 类。将此函数作为参数写入您的绑定函数并将其设置为 itemView 就像这样:
MainRecyclerAdapter.ViewHolder
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view)
fun bind(newsItem: JSONObject,itemClickListener:(Int)->Unit)
//Some Stuff here..
itemView.setOnClickListener itemClickListener(adapterPosition)
在BindViewHolder上使用这个方法
OnBindViewHolder
override fun onBindViewHolder(holder: MainRecyclerAdapter.ViewHolder, position: Int)
holder.bind(news.getJSONObject(position),itemClickListener)
现在您可以在任何活动或片段中编写您的 onClick 函数。只需作为参数。
活动或片段
val itemOnClick: (Int) -> Unit = position ->
newsRecyclerView.adapter!!.notifyDataSetChanged()
Toast.makeText(this.context,"$position. item clicked.",Toast.LENGTH_SHORT).show()
newsRecyclerView.adapter = MainRecyclerAdapter(news,itemClickListener = itemOnClick)
【讨论】:
我的救主!我尝试了所有其他方法,只有这个对我有用。谢谢【参考方案9】:您可以通过使用界面轻松实现此目的
class ExercisesAdapter constructor(val mItemClickListener:ItemClickListener) : RecyclerView.Adapter<RecyclerView.ViewHolder>()
interface ItemClickListener
fun onItemClick(position: Int)
fun onLongClick(position: Int)
inner class MyViewHolder(view:View): RecyclerView.ViewHolder(view)
init
view.setOnClickListener
mItemClickListener.onItemClick(adapterPosition)
view.setOnLongClickListener
mItemClickListener.onLongClick(adapterPosition)
return@setOnLongClickListener true
来自您的 MainActivity
public class MainActivity : ActionBarActivity(), ExercisesAdapter.ItemClickListener
protected override fun onCreate(savedInstanceState: Bundle?)
// set content view etc go above this line
mAdapter = ExercisesAdapter(this)
override fun onItemClick(position: Int)
Toast.makeText(this@MainActivity, "TEST: " + position, Toast.LENGTH_SHORT).show()
override fun onLongClick(position: Int)
//do long click here
【讨论】:
这是迄今为止最简单、最优雅的解决方案。我不知道 WTF Google 在他们从 RecyclerView 中省略 onClickListener 时在想什么,但基于 *** 上的许多 CLOSED 线程,他们真的搞砸了。【参考方案10】:3 个简单步骤:
1.传入适配器的参数如下:
class ListAdapter(private val mListener: (ListItemDataClass) -> Unit)
2。在onBindViewHolder
函数中,像这样使用
override fun onBindViewHolder(holder: YourViewHolder, position: Int)
val item = getItem(position)
holder.itemView.setOnClickListener
item?.let it1 -> mListener.invoke(it1)
3.并在您的活动中,像这样使用
val adapter = ListAdapter
Toast.makeText(this, it.title, Toast.LENGTH_SHORT).show()
【讨论】:
【参考方案11】:适配器构造函数声明
class YourAdapter(private val mListener: (ItemObject) -> Unit) : RecyclerView.Adapter<ViewHolder>()
Adapter::onBindViewHolder
holder.itemView.setOnClickListener
mListener.invoke(item) // <- item instance of ItemObject
如何使用
mTypesWasteAdapter = YourAdapter( it.something())
基本上,您将在 lambda 参数中收到作为 it
的 ItemObject。
【讨论】:
【参考方案12】:我的简单解决方案使用高阶函数和let
作用域函数仅在设置了itemAction
时设置监听器
// Adapter
private var itemAction: ((Item) -> Unit)? = null
fun setItemAction(action: (Item) -> Unit)
this.itemAction = action
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view)
fun setItem(item: Item)
// ...
itemAction?.let
itemView.setOnClickListener it(item)
在活动/片段中
adapter.setItemAction // <- it is Item
// do something with it
【讨论】:
就像以前用于单击侦听器的 java 接口一样。我想要这个 kotlin 的解决方案,谢谢你的代码。【参考方案13】:这是一种不使用接口的简单方法,只需在您的适配器中创建一个 init 块在 viewholder 类中。像这样
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
init
itemView.setOnClickListener
//your code here---
【讨论】:
我希望人们不要再回答这个问题了。它不需要24个答案。尤其是看到这个问题有多老了,当 trait 是 Kotlin 的东西时。 你绝不能在你的适配器中使用点击监听器!我从不重复!【参考方案14】:你可以试试这样的:
public class MainActivity : ActionBarActivity()
protected override fun onCreate(savedInstanceState: Bundle?)
[...]
val adapter = DrawAdapter(::onItemClick)
[...]
fun onItemClick(view: View, position: Int)
//Do work
SAM 转换就像在 Java 8 中一样工作,所以只需使用 lambda:
public class MainActivity : ActionBarActivity()
protected override fun onCreate(savedInstanceState: Bundle?)
[...]
val adapter = DrawAdapter(view, position -> /*Do work*/ )
[...]
【讨论】:
添加完整示例以便更好地理解。【参考方案15】:在 RecyclerView 中,您可以点击 ViewHolder
类中的膨胀视图,并从 onBindViewHolder
回调方法中调用它,例如:
class ViewHolder(view: View) : RecyclerView.ViewHolder(view)
val view = view
val tv_message = view.tv_message
val tv_address = view.tv_address
fun bind(listViewItem: ListViewItem)
view.setOnClickListener(View.OnClickListener
Toast.makeText(
view.context,
"Name: " + listViewItem.name + "/n Address: " + listViewItem.address,
Toast.LENGTH_LONG).show()
)
您可以从适配器onBindViewHolder()
方法调用:
override fun onBindViewHolder(holder: ViewHolder, position: Int)
val listViewItem: ListViewItem = mListViewItems[position]
holder.tv_message.text = listViewItem.name
holder.tv_address.text = listViewItem.address
holder.bind(mListViewItems[position]);
【讨论】:
很好的解决方案,这个对我很有用。谢谢。 这里的listViewItem是属于什么的?【参考方案16】:最后,这是一个不错的解决方案:
MyRecyclerAdapter.kt
class MyRecyclerAdapter(val context: Context, val items : ArrayList<Item>, val clickListener: (Int) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>()
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): RecyclerView.ViewHolder
return MyViewHolder(LayoutInflater.from(context).inflate(R.layout.my_item, parent, false))
override fun getItemCount(): Int
return items.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int)
(holder as MyViewHolder).clickableView.setOnClickListener
clickListener(position)
class MyViewHolder (view: View) : RecyclerView.ViewHolder(view)
val clickableView = view.clickable_view
MainActivity.kt
fun appClickListener(position: Int)
// You got the position of ArrayList
my_recyclerview.adapter = MyRecyclerAdapter(this, myList, clickListener =
appClickListener(it)
)
【讨论】:
未解决的参考:clickable_view @ykonda clickable_view 必须是您在 R.layout.my_item 中添加点击监听器的视图的 ID。【参考方案17】://第一步制作一个类似的界面
interface RecyclerViewClickListener
fun onItemClick(position: String)
fun onLongClick(position: Int)
步骤 2 在 Adapter 类中再传递一个参数作为接口,例如
class ModelAdapter(var item_list: ArrayList<UploadDocument>,var mItemClickListener:RecyclerViewClickListener) : RecyclerView.Adapter<ModelAdapter.ViewHolder>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ModelAdapter.ViewHolder
// create a new view
val view = LayoutInflater.from(parent.context).inflate(R.layout.upload_document_row_item, null)
// create ViewHolder
return ViewHolder(view)
override fun onBindViewHolder(holder: ModelAdapter.ViewHolder, position: Int)
holder.txtRegistrationDoc?.setText(item_list[position].getdocName())
holder.txtCertificate?.setText(item_list[position].getcertificateName())
holder.txtFileSize?.setText(item_list[position].getfileSize())
holder.txtCreatedOn?.setText(item_list[position].getcreatedOn())
holder.txtModifiedOn?.setText(item_list[position].getModifiedDate())
//holder.chkSelected.isChecked = item_list[position].isSelected()
holder.chkSelected.tag = item_list[position].getdocName()
holder. chkSelected!!.setOnCheckedChangeListener buttonView, isChecked ->
if(isChecked)
System.out.println("position>>>"+buttonView.tag.toString())
mItemClickListener.onItemClick(buttonView.tag.toString())
//(context as UploadDocumentActivity::class.java).onClickCalled("your argument here")
/* holder.btn_delete.setOnClickListener(object : View.OnClickListener()
override fun onClick(v: View)
deleteItemFromList(v, position)
)*/
override fun getItemCount(): Int
return item_list.size
/*// confirmation dialog box to delete an unit
private fun deleteItemFromList(v: View, position: Int)
val builder = AlertDialog.Builder(v.getContext())
//builder.setTitle("Dlete ");
builder.setMessage("Delete Item ?")
.setCancelable(false)
.setPositiveButton("CONFIRM",
DialogInterface.OnClickListener dialog, id ->
item_list.remove(position)
notifyDataSetChanged()
)
.setNegativeButton("CANCEL", DialogInterface.OnClickListener dialog, id -> )
builder.show()
*/
class ViewHolder(
itemLayoutView: View) : RecyclerView.ViewHolder(itemLayoutView)
var item_name: TextView
var txtRegistrationDoc: TextViewNormal?=null
var txtCertificate: TextViewNormal?=null
var txtFileSize: TextViewNormal?=null
var txtCreatedOn: TextViewNormal?=null
var txtModifiedOn: TextViewNormal?=null
var chkSelected: CheckBox
init
item_name = itemLayoutView.findViewById(R.id.txt_Name)
txtRegistrationDoc = itemLayoutView.findViewById(R.id.txtRegistrationDoc)
txtCertificate = itemLayoutView.findViewById(R.id.txtCertificate)
txtFileSize = itemLayoutView.findViewById(R.id.txtFileSize)
txtCreatedOn = itemLayoutView.findViewById(R.id.txtCreatedOn)
txtModifiedOn = itemLayoutView.findViewById(R.id.txtModifiedOn)
//btn_delete = itemLayoutView.findViewById(R.id.btn_delete_unit)
chkSelected = itemLayoutView.findViewById(R.id.chk_selected)
//第 3 步在您的活动/片段中
recyclerView?.adapter = ModelAdapter(documentList,object : `in`.mobilepedia.com.gicgwaliarincubationcentre.RecyclerViewClickListener
override fun onItemClick(position: String)
System.out.println("Position>>>>>"+position)
override fun onLongClick(position: Int)
)
【讨论】:
【参考方案18】:科特林
像这样制作你的适配器构造函数
class ViewAdapter(
private val context: Context,
private val mListener: (DataClass) -> Unit
) :
RecyclerView.Adapter<WeekRecyclerViewAdapter.ViewHolder>()
// Your adapter code goes here
在你的onBindViewHolder中,
holder.binding.parentLayout.setOnClickListener
mListener.invoke(items[position]) // <- item instance of ItemObject
在您的 Fragment 中,按如下方式实现
class YourFragment : Fragment(), (DataClass) -> Unit
override fun invoke(p1: DataClass)
//You will get the selected item here
【讨论】:
如何制作两个或多个单元?或者如何通过视图? private val listener: ((DataFile, View) -> Unit)?,因为我需要知道。适配器上的视图,嗯 类型不匹配。必需:((ArrFilesItem, View) → Unit)?找到:() → 单位 我明白了,attachmentAdapter = AttachmentAdapter(attachmentMutableList) 它:ArrFilesItem,视图:视图 ->【参考方案19】:RecyclerItemClickListener
package com.mypackage.custom
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
@Suppress("DEPRECATION")
class RecyclerItemClickListener(context: Context, private val mListener: OnItemClickListener?) : RecyclerView.OnItemTouchListener
private var mGestureDetector: GestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener()
override fun onSingleTapUp(e: MotionEvent): Boolean
return true
)
interface OnItemClickListener
fun onItemClick(view: View, position: Int)
override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean
val childView = view.findChildViewUnder(e.x, e.y)
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e))
mListener.onItemClick(childView, view.getChildPosition(childView))
return true
return false
override fun onTouchEvent(view: RecyclerView, motionEvent: MotionEvent)
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean)
对于活动:
recyclerView!!.addOnItemTouchListener(
RecyclerItemClickListener(this!!, object : RecyclerItemClickListener.OnItemClickListener
override fun onItemClick(view: View, position: Int)
//Write your code here
)
对于片段:
recyclerView!!.addOnItemTouchListener(
RecyclerItemClickListener(this!!.activity!!, object : RecyclerItemClickListener.OnItemClickListener
override fun onItemClick(view: View, position: Int)
//Write your code here
)
【讨论】:
【参考方案20】:这是我的 MainActivity.kt 类,它使用 recyclerview 填充位置数据。它有一个简单的项目点击监听器接口,您可以实现它。
class MainActivity : AppCompatActivity()
private lateinit var recyclerView: RecyclerView
private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var viewManager: RecyclerView.LayoutManager
private var locationArrayList = arrayListOf<Location>()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//create locations
var ny = Location("New York")
var la = Location("Los Angeles")
locationArrayList.addAll(listOf(ny, la))
viewManager = LinearLayoutManager(this)
viewAdapter = LocationsAdapter(locationArrayList)
recyclerView = findViewById<RecyclerView>(R.id.recyclerView).apply
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
setHasFixedSize(true)
// use a linear layout manager
layoutManager = viewManager
// specify an viewAdapter
adapter = viewAdapter
//recycler view click listener implement
recyclerView.addOnItemClickListener(object: OnItemClickListener
override fun onItemClicked(position: Int, view: View)
// Your logic
Toast.makeText(this@MainActivity, locationArrayList[position].locationName, Toast.LENGTH_SHORT).show()
)
//on item click interface
interface OnItemClickListener
fun onItemClicked(position: Int, view: View)
fun RecyclerView.addOnItemClickListener(onClickListener: OnItemClickListener)
this.addOnChildAttachStateChangeListener(object: RecyclerView.OnChildAttachStateChangeListener
override fun onChildViewDetachedFromWindow(view: View?)
view?.setOnClickListener(null)
override fun onChildViewAttachedToWindow(view: View?)
view?.setOnClickListener(
val holder = getChildViewHolder(view)
onClickListener.onItemClicked(holder.adapterPosition, view)
)
)
//end of interface
【讨论】:
【参考方案21】:如果有人对旧方式的实现感兴趣..
我发布了完整的示例,它也减少了您的适配器代码。它使用获取回调的旧模式..
项目级分级
buildscript
ext.kotlin_version = '1.3.10'
repositories
google()
mavenCentral()
jcenter()
dependencies
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"//newly added
classpath 'com.google.gms:google-services:4.1.0' // google-services plugin
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
allprojects
repositories
google()
mavenCentral()
jcenter()
task clean(type: Delete)
delete rootProject.buildDir
应用级 Gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'org.jetbrains.kotlin.android.extensions'//it is used for @Percelize
android
compileSdkVersion 28
dataBinding
enabled = true
androidExtensions
experimental = true
defaultConfig
applicationId 'broadpeak.firebase.learning'
minSdkVersion 19
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
buildTypes
release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
productFlavors
/*kapt
generateStubs = true
*/
dependencies
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.google.firebase:firebase-core:16.0.5'
implementation 'com.google.firebase:firebase-firestore:17.1.3'
implementation 'com.google.firebase:firebase-auth:16.0.5'
implementation 'com.google.firebase:firebase-messaging:17.3.4'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.firebaseui:firebase-ui-auth:4.1.0'
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
////kapt "com.android.databinding:compiler:$android_plugin_version"\ // not required above 3.2.0
///kapt "com.android.databinding:compiler:3.1.4"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'
SubjectListActivity.class
class SubjectListActivity : BaseActivity()
var subjects = mutableListOf<SubjectBO>()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.question_list_activity)
recycler_view.itemAnimator = DefaultItemAnimator()
recycler_view.setHasFixedSize(true)
recycler_view.layoutManager = LinearLayoutManager(this@SubjectListActivity)
db.collection("tagCollection").get().addOnSuccessListener querySnapshot ->
if (querySnapshot.isEmpty())
Log.d(TAG, "onSuccess: LIST EMPTY")
else
// Convert the whole Query Snapshot to a list
// of objects directly! No need to fetch each document.
subjects = querySnapshot.toObjects(SubjectBO::class.java)
if(subjects.size > 0)
recycler_view.adapter = SubjectAdapter(subjects, object : OnRecyclerItemClickListener
override fun onItemClicked(view: View?, position: Int)
var intent = Intent(this@SubjectListActivity,McqActivity::class.java)
intent.putExtra("keyTagBO",subjects.get(position))
startActivity(intent)
);
.addOnFailureListener exception ->
exception.printStackTrace()
SubjectAdapter.class
class SubjectAdapter(items: List<SubjectBO>, onRecyclerItemClickListener: OnRecyclerItemClickListener)
: BaseAdapter<SubjectBO, SubjectViewHolder>(items, onRecyclerItemClickListener)
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): SubjectViewHolder
return SubjectViewHolder(parent, R.layout.item_subject, onRecyclerItemClickListener)
SubjectViewHolder.class
class SubjectViewHolder(parent: ViewGroup, itemLayoutId: Int, onRecyclerItemClickListener:
OnRecyclerItemClickListener) : BaseViewHolder<SubjectBO>(parent, itemLayoutId, onRecyclerItemClickListener)
override fun bindData(data: SubjectBO)
itemView.tvTitle.setText(data.tagName)
BaseAdapter.class
abstract class BaseAdapter<T, U : BaseViewHolder<T>>
(var items: List<T>, var onRecyclerItemClickListener: OnRecyclerItemClickListener)
: RecyclerView.Adapter<U>()
override fun getItemCount(): Int
return items.size
override fun onBindViewHolder(holder: U, pos: Int)
holder.bindData(items.get(pos))
BaseViewHolder.class
abstract class BaseViewHolder<T : BaseModel>(parent: ViewGroup, @LayoutRes itemLayoutId: Int,
var onRecyclerItemClickListener: OnRecyclerItemClickListener) :
RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(itemLayoutId, parent,
false)), View.OnClickListener
override fun onClick(v: View?)
onRecyclerItemClickListener.onItemClicked(v, adapterPosition)
abstract fun bindData(data: T)
init
itemView.setOnClickListener(this)
OnRecyclerItemClickListener.class
interface OnRecyclerItemClickListener
fun onItemClicked(view: View?, position: Int)
【讨论】:
【参考方案22】:您可以通过两种方式在 kotlin 中访问 recyclerview,首先您可以直接在适配器中声明 OnClickListener 并在其中进行重定向,第二种方法是您可以将 onclick 重定向到您设置了回收器适配器的片段/活动
1.
class CartAdapter(context: Context) : RecyclerView.Adapter<CartAdapter.ViewHolder>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_cart, parent, false));
override fun getItemCount(): Int
return 10;
override fun onBindViewHolder(holder: ViewHolder, position: Int)
holder.itemView.rtbProductRating.setOnClickListener
var iNavigation= Intent(context,MainActivity::class.java)
iNavigation.flags= Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT
context.startActivity(iNavigation)
// directly redirect your activity from adapter
class ViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView)
第二种方法是将您的适配器点击重定向到片段/活动,然后从那里重定向您的活动,而不是从适配器重定向
class CartAdapter(context: Context, onClickListener: View.OnClickListener) : RecyclerView.Adapter<CartAdapter.ViewHolder>()
var context = context
var onClickListener = onClickListener
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_cart, parent, false));
override fun getItemCount(): Int
return 10;
override fun onBindViewHolder(holder: ViewHolder, position: Int)
//set your position to the view
holder.itemView.rtbProductRating.tag = position
//redirect click to the fragment
holder.itemView.rtbProductRating.setOnClickListener
onClickListener.onClick(holder.itemView.rtbProductRating)
// holder.itemView.tv_waybill_count.text = holder.itemView.context.getString(R.string.waybills,5)
class ViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView)
Your fragment will look like:
class CartFragment: BaseFragment(),View.OnClickListener
override val layout= R.layout.frg_cart
override fun onClick(v: View?)
var position=v?.tag as Int
if(position==0)
var iNavigation= Intent(this,MainActivity::class.java)
iNavigation.flag=Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT
startActivity(iNavigation)
override fun onActivityCreated(savedInstanceState: Bundle?)
super.onActivityCreated(savedInstanceState)
listener()
private fun listener()
cart_rv.adapter=CartAdapter(activity,this)
【讨论】:
【参考方案23】:哦,到底有人会喜欢这个 我们都将编辑和垃圾箱图像放在 recyclerview 中,并希望在单击它们时发生一些事情。这是我们的 Kotlin 示例
这是在适配器中膨胀的卡片视图
<RelativeLayout
android:id="@+id/editCLICK"
android:layout_
android:layout_
android:layout_marginStart="370dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:paddingTop="12dp">
<ImageView
android:id="@+id/ivEdit"
android:layout_
android:layout_
android:background="@color/color_Transparent"
android:src="@drawable/ic_edit"
android:tint="@color/color_lightBlue" />
</RelativeLayout>
然后在Adapter中我们做一些绑定
override fun onBindViewHolder(holder: ParentViewHolder, position: Int)
val items = parentList[position]
holder.item.text = items.dept
holder.editCLICK.setOnClickListener
val i = Intent(context, EnterParentActivity::class.java)
i.putExtra("FROM", "U")
i.putExtra("MainActId",items.idD)
i.putExtra("PFK",items.fkD)
i.putExtra("ET",items.dept)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(i)
inner class ParentViewHolder(view: View):RecyclerView.ViewHolder(view)
var item: TextView = view.findViewById(R.id.tvDept) as TextView
var editCLICK: RelativeLayout = view.findViewById(R.id.editCLICK) as RelativeLayout
简单快速可靠的享受
【讨论】:
很好,但请不要在其中使用相对布局【参考方案24】:我想出了这个解决方案,使用伴随对象和界面在单击行时打开一个活动。该活动是从主要活动中打开的,因为我必须在离开前保存列表状态。
适配器
class MyAdapter(
val dataList: List<objects.ListObject>, val listener: ItemClickListener
) : RecyclerView.Adapter<MyAdapter.ListViewHolder>()
companion object
var mClickListener: ItemClickListener? = null
interface ItemClickListener
fun clickRow(position: Int)
override fun onBindViewHolder(holder: MyAdapter.ListViewHolder, position: Int)
holder.bindData(
...
)
mClickListener = listener
holder.itemView.setOnClickListener view ->
mClickListener?.clickRow(position)
...
主要活动
val context = this
private lateinit var mMyAdapter: MyAdapter
fun initList()
mMyAdapter =
MyAdapter(dataList, object : MyAdapter.ItemClickListener
override fun clickRow(position: Int)
openActivityListItems(position)
)
fun openActivityListItems(position : Int)
recyclerViewState = mListView.getLayoutManager()?.onSaveInstanceState()
val intent = Intent(context, ListItems::class.java)
intent.putExtra("Parameter1", dataList[position].Parameter1)
intent.putExtra("Parameter2", dataList[position].Parameter2)
context.startActivity(intent)
【讨论】:
以上是关于Kotlin 中的 RecyclerView itemClickListener [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin android中的RecyclerView itemClickListener
使用 kotlin 的 recyclerview 中的数据绑定导致问题
如何将数据从 RecyclerView 传递到 Kotlin 中的 DialogFragment?
当 Kotlin 中的数据发生变化时,如何在 RecyclerView 中重新绑定项目?