Home > Blockchain >  Returning position from RecyclerView(Adapter)
Returning position from RecyclerView(Adapter)

Time:07-27

I have two class and I would like to be able to change the imageview(e.g. upmainchar) in select_characters_life after clicking the item in recyclerview.

class select_characters_life : AppCompatActivity() {
    private lateinit var adapter: MyAdapter
    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_select_characters_life)

        var downplayerlist = findViewById<RecyclerView>(R.id.listDownPlayer)
        var upplayerlist = findViewById<RecyclerView>(R.id.listUpPlayer)
        val data = ArrayList<example_adapter_data>()

        data.add(example_adapter_data(R.mipmap.pingu))
        data.add(example_adapter_data(R.mipmap.foczyn))
        data.add(example_adapter_data(R.mipmap.wilk))
        data.add(example_adapter_data(R.mipmap.dudu))
        
        var upmainchar = findViewById<ImageView>(R.id.imUpMainCharacterLife)
        var downmainchar = findViewById<ImageView>(R.id.imDownMainCharacterLife)
        
        upmainchar.setImageResource(data[0].image)
        downmainchar.setImageResource(data[0].image)
        
        downplayerlist.adapter = MyAdapter(data)
        upplayerlist.adapter = MyAdapter(data)

and adapter class

class MyAdapter(private val lista: List<example_adapter_data>):RecyclerView.Adapter<MyViewHolder>() {
   
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
       
        val layoutInflater = LayoutInflater.from(parent.context)
        val select_characters = layoutInflater.inflate(R.layout.characters_select_life_mode, parent, false)
        return MyViewHolder(select_characters)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val dane = lista[position]
        holder.image.setImageResource(dane.image)

        holder.itemView.setOnClickListener {
        }}

    override fun getItemCount(): Int { return lista.size}
}
class MyViewHolder(val view: View): RecyclerView.ViewHolder(view){
    var image = itemView.findViewById<ImageView>(R.id.imPlayer)
}

I think that there are two ways to resolve this problem. The first one is adding a new view in the adapter class (first class layout). The preferable one is returning position value in adapter class to the first class. Thank you in advance!

CodePudding user response:

Easiest and most Kotlin-y way is to pass a callback function into the adapter. You could do it in the constructor because you might as well!

class MyAdapter(
    private val lista: List<example_adapter_data>,
    private val callback: (Int) -> Unit
):RecyclerView.Adapter<MyViewHolder>() {

In case you didn't know the callback's parameter's type, (Int) -> Unit, means a function that takes a single Int parameter and returns Unit, aka doesn't return anything. It's a function that takes an Int and does something with it.

So you can call that function inside your click listener:

holder.itemView.setOnClickListener {
    // invoke the callback, passing it the position of the clicked item
    callback(position)
}

Now all you need to do is write a function to do something with that Int! So in your Activity:

// you can put the lambda outside the parentheses since it's the last parameter
downplayerlist.adapter = MyAdapter(data) { position ->
    // handle the data passed as a result of a click in this adapter's list
    downmainchar.setImageResource(data[position].image)
}

An alternative is to just pass the data item itself, which is a little cleaner than taking the position in the list view and treating it as an index in a data set in an Activity (even though it works out as the same thing in the current code)

// adapter constructor
private val callback: (example_adapter_data) -> Unit

// adapter onBindViewHolder
holder.itemView.setOnClickListener { callback(lista[position]) }

// activity
downplayerlist.adapter = MyAdapter(data) { item ->
    downmainchar.setImageResource(item.image)
}

I feel like that's cleaner - it doesn't force a hard link between the internal representation in the Adapter and the data set the Activity holds. You just pass the item that was clicked to the callback, and that handles it however it needs to. In fact this way, the Activity doesn't need to hold the data anymore! It can just pass it to the adapter, and when an item comes back in, it just needs to take its image resource ID and display it. It doesn't need to have a copy of the full data set, which isn't something the UI stuff like Activities and Fragments should be concerned with

CodePudding user response:

In MyAdapter

private var onClickListener: (position: Int) -> Unit = {}

fun setOnClickListener(clickListener: (position: Int) -> Unit){
     onClickListener = clickListener
}

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

    holder.itemView.setOnClickListener {
       onClickListener.invoke(position)
    }
  }
}

In activity

  upplayerlist.adapter = MyAdapter(data).apply{
        setOnClickListener{adapterPosition ->
           //do what you need for adapterPosition

      }
 }
  • Related