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