web-dev-qa-db-fra.com

getActivity () / context dans un ViewHolder dans Kotlin Android

Je crée un ViewHolder et un adaptateur pour un fragment et lorsque j'essaie de créer un OnClick pour le ViewHolder, aucun des contextes que je passe ne fonctionne. Il n'y a pas de activity de getActivity() que je puisse utiliser, et p0!!.context ni itemView.context travailler soit. D'où dois-je obtenir mon contexte et comment le référencer?

package com._________.criminalintent

import Android.os.Bundle
import Android.support.v4.app.Fragment
import Android.support.v7.widget.LinearLayoutManager
import Android.support.v7.widget.RecyclerView
import Android.view.LayoutInflater
import Android.view.View
import Android.view.ViewGroup
import Android.widget.TextView
import Android.widget.Toast

class CrimeListFragment: Fragment() {
    private var mCrimeRecyclerView: RecyclerView? = null
    private var mAdapter: CrimeAdapter? = null

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    // fragment_crime_list.xml has a RecyclerView element = crime_recycler_view
    // inflate the fragment into the activity
        val view = inflater!!.inflate(R.layout.fragment_crime_list, container, false)

        // grab the recyclerView and give it a required layoutManager
        mCrimeRecyclerView = view.findViewById(R.id.crime_recycler_view)
        mCrimeRecyclerView!!.layoutManager = LinearLayoutManager(activity)
        updateUI()
        return view
    }

    private fun updateUI() {
        val crimeLab = CrimeLab.get(activity)
        val crimes = crimeLab.getCrimes()
        mAdapter = CrimeAdapter(crimes)
        // Connect the adapter to the recyclerView
        mCrimeRecyclerView!!.adapter = mAdapter
    }

    /**
     * in Kotlin, we must give the view passed into the constructor directly
     * as a substitute for a super() call
     *
     * create a ViewHolder that holders the crime list item's view
     *
     * super(itemView) = super(inflater!!.inflate(R.layout.list_item_crime, parent, false))
     * MUST give it the direct value in Kotlin
     */
    private class CrimeHolder(inflater: LayoutInflater?, parent: ViewGroup):
        RecyclerView.ViewHolder(inflater!!.inflate(R.layout.list_item_crime, parent, false)),
        View.OnClickListener {

        private var mCrime: Crime? = null

        /**
         * When given a crime, this CrimeHolder will update the title and date for this Crime
         */
        fun bind(crime: Crime) {
           mCrime = crime
            val titleTextView = itemView.findViewById<TextView>(R.id.crime_title)
            val dateTextView = itemView.findViewById<TextView>(R.id.crime_date)
            titleTextView.text = mCrime!!.mTitle
            dateTextView.text = mCrime!!.mDate.toString()
        }

        override fun onClick(p0: View?) {

            Toast.makeText(WHAT_TO_PUT_HERE, "${mCrime!!.mTitle} clicked!", Toast.LENGTH_SHORT / 2)
                .show()
    }
}


    private class CrimeAdapter(private var mCrimes: MutableList<Crime>):
        RecyclerView.Adapter<CrimeHolder>() {

        /**
         * - Calls our CrimeHolder to make our custom ViewHolders
         * - Called by RecyclerView when it needs a new view to display
         * - Gets the layoutInflater from the ViewGroup and returns a CrimeHolder of it
         */
        override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): CrimeHolder
        = CrimeHolder(LayoutInflater.from(parent!!.context), parent)


        /**
         * Bind the crime (data) to the CrimeHolder
         */
        override fun onBindViewHolder(holder: CrimeHolder?, position: Int) {
            holder!!.bind(mCrimes[position])
        }

        /**
         * Sees how many items are in the RecyclerView that need to be shown
         */
        override fun getItemCount(): Int = mCrimes.size
    }
}
5
user3338275

Dans votre implémentation, vous pouvez utiliser en toute sécurité Context à partir de View fourni à votre OnClickListener

override fun onClick(p0: View) {
          Toast.makeText(p0.context, "${mCrime!!.mTitle} clicked!", Toast.LENGTH_SHORT / 2)
                .show()
    }

N'oubliez pas de régler onclick:

fun bind(crime: Crime) {
           mCrime = crime
            val titleTextView = itemView.findViewById<TextView>(R.id.crime_title)
            val dateTextView = itemView.findViewById<TextView>(R.id.crime_date)
            titleTextView.text = mCrime!!.mTitle
            dateTextView.text = mCrime!!.mDate.toString()
            itemView.setOnClickListener(this)
}

De plus, toutes les classes Kotlin sont imbriquées (static) par défaut. Votre private class CrimeHolder Équivaut donc à private static class CrimeHolder En Java. C'est pourquoi vous n'avez pas accès à getActivity() depuis CrimeHolder

6
rafal

Utilisation itemView.context propriété à l'intérieur de votre support.

Edit: La raison pour laquelle votre onClick ne "fonctionne" pas (n'est pas appelée) est que vous n'avez pas enregistré le onClickListener, par exemple:

itemView.setOnClickListener(this)

à l'intérieur de votre support init ou bind.

1
maciekjanusz
 itemView.setOnClickListener {
                Toast.makeText(itemView.context, "Item is clicked $position", Toast.LENGTH_SHORT).show() }
        }
0
HandyPawan