'How to make item selectable in recycler view and use it?

I have followed android developer documents to create the recycler view. But now I would like to make the item selectable.

Currently have created itemAdapter.kt

class ItemAdapter(
    private val context: Context,
    private val dataset: List<Mode>,
    private val itemClickListener: MainActivity
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {
    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder.

    class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
        val textView: TextView = view.findViewById(R.id.item_title)
    }

    /**
     * Create new views (invoked by the layout manager)
     */
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
        // create a new view
        val adapterLayout = LayoutInflater.from(parent.context)
            .inflate(R.layout.list_item, parent, false)

        return ItemViewHolder(adapterLayout)
    }

    /**
     * Replace the contents of a view (invoked by the layout manager)
     */
    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        val item = dataset[position]
        holder.textView.text = context.resources.getString(item.stringResourceId)
        holder.itemView.setOnClickListener {
            itemClickListener.onItemClick(item) //here we are sending the mode object using interface
        }
    }

    /**
     * Return the size of your dataset (invoked by the layout manager)
     */
    override fun getItemCount() = dataset.size

    interface ItemClickListener {
        fun onItemClick(mode: Mode)
    }

}

Then there is data file called Modes.kt

class Modes {
    fun loadModes(): List<Mode> {
        return listOf(
            Mode(R.string.height),
            Mode(R.string.hleveldistance),
        )
    }
}

Then there is model file called Model.kt

data class Mode(val stringResourceId: Int)

How do I get the selected item for my function in the mainactivity.

class MainActivity : AppCompatActivity() {

    //private var etCommand: EditText? = null
    private var tvPalaute: TextView? = null
    private val modes = Modes().loadModes()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Initialize modes

 val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
        recyclerView.adapter = ItemAdapter(this, modes, this)
        // Use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        recyclerView.setHasFixedSize(true)

        //val etCommand: EditText = findViewById(R.id.et_command)
        val etSubmit: Button = findViewById(R.id.btn_submit)
        val etMeasure: Button = findViewById(R.id.btn_measure)

        tvPalaute = findViewById(R.id.tvPalaute)


        etSubmit.setOnClickListener {
                Toast.makeText(this, "Haetaan laite", Toast.LENGTH_SHORT).show()
                openActivityForResult()
        }

        etMeasure.setOnClickListener {
                Toast.makeText(this, "Aloitetaan mittaus", Toast.LENGTH_SHORT).show()
                openMeasureActivityForResult()
        }
    }

    fun onItemClick(mode: Mode) {
//openMeasureActivityForResult(mode) // update method to receive mode as an argument
        Log.d(mode.code, "mode code")
        Toast.makeText(this, "Mode is $mode", Toast.LENGTH_SHORT).show()
    }

    private fun openMeasureActivityForResult(mode: Mode) {
        val measureAction = "com.app.app.m"
        val intent = Intent()
        intent.action = measureAction
        //val selectedMode = mode?.Id
        //var mode = modes[selectedMode!!]
        intent.putExtra("Mode", mode?.code)
        Log.d(intent.toString(), "intent")
        intent.putExtra("AppName", "Example App")
        //if (!String.toString().isNullOrEmpty(Device))
        //{
          //  intent.putExtra("Device", Device);
        //}
        measureLauncher.launch(intent)
    }

This is my current state of the code. What should the openmeasureactivity function get as it parameter? And is the code looking allright since itemadapter is not in use now. And does the selected item look correct?



Solution 1:[1]

You can user interface to pass objects to the activity.

Create an interface ItemClickListener with a method named onItemClick with a parameter of type, whatever you want to receive in your activity. For here use Mode

interface ItemClickListener {
    fun onItemClick(mode: Mode)
}

In your activity or fragment implement this interface, and override the onItemClick method to perform any operations on the selected Mode object.

class MainActivity : ItemClickListener {

    override fun onItemClick(mode: Mode) {
        openMeasureActivityForResult(mode) // update method to receive mode as an argument
    }

    private fun openMeasureActivityForResult(mode: Mode) { //use mode here
        val measureAction = "com.app.app.m"
        val intent = Intent()
        intent.action = measureAction
        //var mode = modes[SelectedMode] <-- here the selected value
        //intent.putExtra("Mode", mode.Code); <-- also here
        intent.putExtra("AppName", "Example App")
        //if (!String.toString().isNullOrEmpty(Device))
        //{
          //  intent.putExtra("Device", Device);
        //}
        measureLauncher.launch(intent)
    }
}

Change ItemAdapter to accept ItemClickListener in its constructor

class ItemAdapter(
    private val context: Context,
    private val dataset: List<Mode>,
    private val itemClickListener: ItemClickListener
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {


}

Inside onBindViewHolder() set a click listener to the holders itemView and pass mode object using the itemClickListener

override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        val item = dataset[position]
        holder.textView.text = context.resources.getString(item.stringResourceId)
        holder.itemView.setOnClickListener {
            itemClickListener.onItemClick(item) //here we are sending the mode object using interface
        }
    }

In activity or fragment, when you create adapter just pass the instance of ItemClickListener's interface, we can pass it using this as we've already implemented it above.

val adapter = ItemAdapter(
    context,
    modeList,
    this 
)

Solution 2:[2]

I had the same problem, I made an interface for the on click, then in your fragment you override this fun with whatever you want to do.

// Here I add --> val itemClickListener: ItemClickListener
class MovieAdapter(
private val movies: List<Mode>, 
val itemClickListener: ItemClickListener) : RecyclerView.Adapter<MovieAdapter.ViewHolder>() {

    private lateinit var context: Context

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        private val binding = ItemMovieBinding.bind(itemView)

        fun bind(mode: Mode) {
            // Here we set the setOnClickListener
            itemView.setOnClickListener {itemClickListener.onClick(mode)}
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        context = parent.context
        // R.layout.item_mode --> change to yor layout
        return ViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_mode, parent, false)
        )
    }

    /**
     * Returns the size of the list
     */
    override fun getItemCount(): Int = movies.size

    /**
     * Called by RecyclerView to display the data at the specified position.
     */
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(movies[position])
    }
}
// The interface we can use in the fragment
interface ItemClickListener{
    fun onClick(mode: Mode)
}

then you can use the interface in your fragment:

override fun onClick(mode: Mode) {
   // here you can use the object
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Praveen
Solution 2