web-dev-qa-db-fra.com

RecyclerView onitemClickListener in Kotlin

J'écris ma première application sous Kotlin après 3 ans d'expérience avec Android . Je ne comprends pas comment utiliser itemClickListener avec un RecyclerView dans Kotlin.

J'ai essayé l'approche trait (edit: now interface), très semblable à 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)
  }
}

Cela semblait très superflu, alors j’ai essayé l’approche de la classe interne:

inner class ItemClickListener {
    fun onItemClick(view: View, position: Int) {
        startActivityFromFragmentForResult<SelectExerciseActivity>(SELECT_EXERCISES)
    }
}

Et ensuite, définissez simplement le port d'écoute de l'adaptateur comme suit:

val adapter = WorkoutsAdapter(ItemClickListener())

Mais je ne suis toujours pas satisfait de cela, car je pense qu’il pourrait y avoir une meilleure méthode, plus propre. J'essaie essentiellement de réaliser quelque chose comme ceci: RecyclerView onClick

Aucune suggestion?

J'ai fini par aller avec une variante de la réponse approuvée

Défini la fonction dans l'activité:

val itemOnClick: (View, Int, Int) -> Unit = { view, position, type ->
    Log.d(TAG, "test")
}

Transmettez la fonction elle-même à l'adaptateur comme ceci:

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

Fonction d'extension par boucle dans la réponse approuvée ci-dessous.

fun <T : RecyclerView.ViewHolder> T.onClick(event: (view: View, position: Int, type: Int) -> Unit): T {
    itemView.setOnClickListener {
        event.invoke(it, getAdapterPosition(), getItemViewType())
    }
    return this
}
20
AfzalivE

J'ai une approche un peu différente. Vous pouvez créer une extension pour votre ViewHolder

fun <T : RecyclerView.ViewHolder> T.listen(event: (position: Int, type: Int) -> Unit): T {
    itemView.setOnClickListener {
        event.invoke(getAdapterPosition(), getItemViewType())
    }
    return this
}

Puis utilisez-le dans un adaptateur comme celui-ci

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

    }
}

Je travaille avec mes collègues sur library en fournissant de telles extensions.

16
Damian Petla

Ma solution est comme une combinaison des précédentes avec un appel super propre de l'activité. 

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

Au cas où quelqu'un voudrait une réponse plus sans superflu, j'ai essayé ce qui suit - qui est très similaire à la solution de AfzalivE :

Dans ma classe Adapter, j'ai passé la clickListener en tant que paramètre. Sur onBindViewHolder, j'ai utilisé setOnClickListener pour appeler clickListener et gérer l'événement 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)...

}

Remarque : J'avais besoin d'une référence provenant du conteneur de mon élément de liste (la vue racine), qui dans ce cas est containerView

Ensuite, j'ai passé mon objet en paramètre sans avoir besoin de chercher à nouveau dans une liste et de le manipuler directement dans ma classe Activity, au moment où j'ai défini l'adaptateur:

MyActivity.kt :

myRecyclerView?.adapter = MyAdapter(mObjects) {
    Log.e("Activity", "Clicked on item ${it.itemName}")
}  

Mettre à jour

Si vous devez connaître la position de l'élément sur lequel vous avez cliqué, définissez-le simplement comme paramètre dans le rappel, puis renvoyez-le plus tard. Notez le val clickListener: (MyObject, Int) -> Unit ci-dessous:

MyAdapter.kt

class MyAdapter constructor(objects: ArrayList<MyObject>, val clickListener: (MyObject, Int) -> Unit) : RecyclerView.Adapter<MyAdapter.Holder>() {
    // Rest of the code...

Ensuite, sur onBindViewHolder(), vous passez la position lorsque vous appelez la méthode de rappel:

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

Et sur MyActivity.kt , vous devrez changer la manière dont vous configurez l'adaptateur pour pouvoir obtenir la position. Comme ça:

myRecyclerView?.adapter = MyAdapter(mObjects) { itemDto: MyObject, position: Int ->
        Log.e("MyActivity", "Clicked on item  ${itemDto.someItemPropertyLikeName} at position $position")
    }
5
notapotato

Je pense que la solution la plus élégante est de donner cette responsabilité à recyclerView et non de la visualiser ni même de l’adapter.

pour cela nous avons besoin de:

1: Créer un fichier RecyclerItemClickListener

class RecyclerItemClickListener(private val mRecycler: RecyclerView, private val clickListener: OnClickListener? = null, private val longClickListener: OnLongClickListener? = 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?.onItemClick(position, v)
                longClickListener?.onLongItemClick(position, v)
            }
        }
    }

    interface OnClickListener {
        fun onItemClick(position: Int, view: View)
    }

    interface OnLongClickListener {
        fun onLongItemClick(position: Int, view: View)
    }
}

2: Créer/Ajouter des extensions pour RecyclerView:

import Android.support.v7.widget.RecyclerView
import com.decathlon.manager.internal.common.RecyclerItemClickListener

fun RecyclerView.affectOnItemClick(listener: RecyclerItemClickListener.OnClickListener) {
    this.addOnChildAttachStateChangeListener(RecyclerItemClickListener(this, listener, null))
}

fun RecyclerView.affectOnLongItemClick(listener: RecyclerItemClickListener.OnLongClickListener) {
    this.addOnChildAttachStateChangeListener(RecyclerItemClickListener(this, null, listener))
}

fun RecyclerView.affectOnItemClicks(onClick: RecyclerItemClickListener.OnClickListener, onLongClick: RecyclerItemClickListener.OnLongClickListener) {
    this.addOnChildAttachStateChangeListener(RecyclerItemClickListener(this, onClick, onLongClick))
}

3: Et enfin l'utilisation (je suppose que vous utilisez kotlinx)

import kotlinx.Android.synthetic.main.{your_layout_name}.*
class FragmentName : Fragment() {
    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        recycler.affectOnItemClick(object : RecyclerItemClickListener.OnClickListener {
            override fun onItemClick(position: Int, view: View) {
                //todo
            }
        })
    }
}
3
Maxime Jallu

Vous pouvez essayer quelque chose comme:

public class MainActivity : ActionBarActivity() {
    protected override fun onCreate(savedInstanceState: Bundle?) {
        [...]
        val adapter = DrawAdapter(::onItemClick)
        [...]
    }
}

fun onItemClick(view: View, position: Int) {
    //Do work
}

et la conversion SAM fonctionne comme en Java 8, utilisez donc un lambda

public class MainActivity : ActionBarActivity() {
    protected override fun onCreate(savedInstanceState: Bundle?) {
        [...]
        val adapter = DrawAdapter({view, position -> /*Do work*/ })
        [...]
    }
}
2
D3xter

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

Pour l'activité:

 recyclerView!!.addOnItemTouchListener(
                RecyclerItemClickListener(this!!, object : RecyclerItemClickListener.OnItemClickListener {
                    override fun onItemClick(view: View, position: Int) {
                        //Write your code here
                    }
                })

Pour le fragment:

recyclerView!!.addOnItemTouchListener(
                RecyclerItemClickListener(this!!.activity!!, object : RecyclerItemClickListener.OnItemClickListener {
                    override fun onItemClick(view: View, position: Int) {
                        //Write your code here
                    }
                })
1
Kunsh Technologies

Désolé pour le retard, J'ai reçu une réponse géniale de this link et c'était en Java .. J'ai fait quelques devoirs et les ai convertis en Kotlin ..

Maintenant, cela fonctionne correctement .. Voici le code,

Créez une classe nommée 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) {}}

et y accéder depuis Activité/Fragment en tant que

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")
        }
    }))
1
Rajesh Naddy

Dans RecyclerView, vous pouvez placer un clic sur une vue agrandie à l'intérieur de la classe ViewHolder et l'appeler depuis la méthode de rappel onBindViewHolder, par exemple:

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

Vous pouvez appeler depuis la méthode adapter 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]);
}
1
rakesh rajput

Déclaration du constructeur de l'adaptateur  

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

Adaptateur :: onBindViewHolder

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

Comment utiliser

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

Fondamentalement, vous recevrez l'objet ItemObject sous la forme it dans l'argument lambda.

1
Lucas Montano

Enfin, voici une solution pratique de Nice:

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

Vous n'avez pas besoin d'écrire une fonction d'extension sur ViewHolder ou quelque chose comme ça.
Meilleur entrainement; use Fonction d'ordre supérieur  

MainRecyclerAdapter

class MainRecyclerAdapter(val news: JSONArray, private val itemClickListener: (Int) -> Unit) : RecyclerView.Adapter<MainRecyclerAdapter.ViewHolder>() {}

Ajoutez simplement une fonction d'ordre supérieur. comme itemClickListener, puis accédez à la classe ViewHolder. Ecrivez cette fonction dans votre fonction bind en tant que paramètre et définissez-la sur 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) }

        }
    }

Utilisez cette méthode onBindViewHolder

OnBindViewHolder

 override fun onBindViewHolder(holder: MainRecyclerAdapter.ViewHolder, position: Int) {

        holder.bind(news.getJSONObject(position),itemClickListener)
    }

Et maintenant, vous pouvez écrire votre fonction onClick dans n'importe quelle activité ou fragment .. Donnez-nous simplement un paramètre.

Activité ou fragment

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)
1
faskN

Oh, qu'est-ce qui pourrait plaire à quelqu'un? __. Nous plaçons tous des images de montage et de corbeille dans une vue de recyclage et souhaitons que quelque chose se produise lorsque l'utilisateur clique dessus. Voici notre exemple Kotlin

Ceci est dans une vue de carte qui est gonflée dans l'adaptateur

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

puis dans l'adaptateur nous faisons une liaison 

    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
}

Simple rapide et fiable profiter

0
Grendel

Légèrement différent, basé sur denwehrle

Pour utiliser sur un fragment, à l'intérieur de OnCreateView

 adapter.onItemClick = {it ->
    //do something
 }

Ajouter dans la classe d'adaptateur:

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

Vous pouvez avoir un accès à Recyclerview dans kotlin de deux manières différentes: vous pouvez d'abord déclarer directement OnClickListener dans l'adaptateur et y effectuer une redirection; d'autre part, vous pouvez rediriger votre onclick vers un fragment/activité lorsque vous avez défini l'adaptateur de recycleur 

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

La deuxième façon que vous pouvez avoir est de rediriger votre adaptateur en cliquant sur fragment/activité, puis de rediriger votre activité à partir de là au lieu de rediriger depuis un adaptateur.

 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)
    }
}
0
Android Geek

Ajouter le code ClickListener sur onBindViewHolder fun

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
}
0
iOS Lifee

Voici ma classe MainActivity.kt qui utilise recyclerview pour renseigner les données de localisation. Il possède une interface d'écoute de clic sur élément simple que vous pouvez implémenter.

    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
    }
0
Ronny Kibet

Si quelqu'un s'intéresse à l'ancienne mise en œuvre .. 

J'ai posté un exemple complet qui réduit également le code de votre adaptateur. Il utilise l'ancien modèle d'obtention de rappel ..

Niveau de projet

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
}

Niveau d'application

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)
}
0
Xar E Ahmer