RecyclerView itemClickListener в Котлине

Я пишу свое первое приложение в Kotlin после 3-летнего опыта работы с Android. Просто запутался, как использовать itemClickListener с RecyclerView в Котлине.

Я пробовал подход (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([email protected], "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

Любые предложения?

Закончено с изменением одобренного ответа

Определена функция в активности:

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
}

Ответ 1

У меня есть немного другой подход. Вы можете создать расширение для своего 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) {

    }
}

Я работаю с коллегами по библиотеке, предоставляя такие расширения.

Ответ 2

Мое решение похоже на сочетание предыдущих с супер чистым вызовом из активности.

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

ContactActivity:

override fun setupRecyclerAdapter() {
    recyclerView.adapter = contactAdapter
    recyclerView.layoutManager = LinearLayoutManager(this)

    contactAdapter.onItemClick = { contact ->

        // do something with your item
        Log.d("TAG", contact.email)
    }
}

Ответ 3

Извините за задержку, Получил отличный ответ по этой ссылке, и он был на Яве.. Сделал домашнюю работу и преобразовал ее в 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")
        }
    }))

Ответ 4

В случае, если кто-либо ищет более беззаботный ответ, я попробовал следующее: это очень похоже на решение от AfzalivE:

В моем классе адаптера я передал clickListener в качестве параметра. В onBindViewHolder я использовал setOnClickListener для вызова clickListener и обработки события click.

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

Ответ 5

Немного другое, основанное на 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])
            }
        }
}

Ответ 6

Обновлено в 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*/ }
    }
}

Ответ 7

Объявление конструктора адаптера

class YourAdapter(private val mListener: (ItemObject) -> Unit) : RecyclerView.Adapter<ViewHolder>()

Адаптер:: onBindViewHolder

holder.itemView.setOnClickListener {
    mListener.invoke(item) // <- item instance of ItemObject
}

Как использовать

mTypesWasteAdapter = YourAdapter({ it.something()})

В принципе, вы получите ItemObject как it в аргументе лямбда.

Ответ 8

Вы можете попробовать что-то вроде:

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*/ })
        [...]
    }
}

Ответ 9

Добавить код ClickListener в onBindViewHolder

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
}

Ответ 10

Вам не нужно писать функцию расширения для 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) }

        }
    }

Используйте этот метод onBindViewHolder

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)

Ответ 11

Наконец, вот хорошее рабочее решение:

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

Ответ 12

Вы можете легко достичь этого с помощью интерфейса

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)
                [email protected] true
            }
        }
    }
}

От вашей основной деятельности

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([email protected], "TEST: " + position, Toast.LENGTH_SHORT).show()
    }

    override fun onLongClick(position: Int) {
        //do long click here
    }
}

Ответ 13

В RecyclerView вы можете нажимать на раздутый вид внутри класса ViewHolder и вызывать его из onBindViewHolder обратного вызова 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]);
}

Ответ 14

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

Ответ 15

Мое простое решение, использующее функцию высшего порядка и функцию видимости 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
}

Ответ 16

Два способа получить доступ к recyclerview в kotlin - это сначала вы можете прямо объявить OnClickListener в адаптере и сделать перенаправление внутри него, а во-вторых, вы можете перенаправить свой onclick в фрагмент/активность, где вы установили адаптер recycler

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

Ответ 17

О, черт возьми, кому-то это может понравиться. Мы все помещаем редактирование и мусорную корзину в наше окно повторного просмотра и хотели бы, чтобы что-то происходило, когда на них нажимали. Вот наш пример Kotlin

Это в виде карты, которая надувается в адаптере

    <RelativeLayout
    android:id="@+id/editCLICK"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:layout_marginStart="370dp"
    android:paddingLeft="6dp"
    android:paddingRight="6dp"
    android:paddingTop="12dp">

    <ImageView
        android:id="@+id/ivEdit"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="@color/color_Transparent"
        android:src="@drawable/ic_edit"
        android:tint="@color/color_lightBlue" />

</RelativeLayout>

затем в адаптере мы делаем некоторые привязки

    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
}

Простое быстрое и надежное наслаждение

Ответ 18

Вот мой класс 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([email protected], 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
    }

Ответ 19

Если кто-то заинтересован в реализации старого способа..

Я опубликовал полный пример, который также уменьшает код вашего адаптера. Он использует старый шаблон получения обратного вызова.

Gradle уровня проекта

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([email protected])

        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([email protected],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)
}

Ответ 20

//Шаг 1 сделать интерфейс похожим

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 Внутри вашей деятельности /Frgament

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) {

        }

    })

Ответ 21

Я придумал это решение, чтобы открыть действие при щелчке строки, используя сопутствующий объект и интерфейс. Действие открывается из основного действия, так как мне пришлось сохранить состояние списка перед выходом.

адаптер

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

Ответ 22

Котлин

Сделайте так, чтобы конструктор вашего адаптера был таким

    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
        }

В своем фрагменте реализуйте, как показано ниже

class YourFragment : Fragment(), (DataClass) -> Unit {
    override fun invoke(p1: DataClass) {

        //You will get the selected item here

    }

Ответ 23

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