I'm new in Android dev.
In my code i don't using onClick method, but i using setOnClickListener and Callback. The main problem that is in this way i don't know how to get the position of the item in RecyclerView.
Here is my Adapter:
class TestAdapter(val test : ArrayList<Test>, private val testAdapterCallback: (Test, Int)->Unit) : RecyclerView.Adapter<TestAdapter.ViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.test_view_item, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return test.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val num : Test = test[position]
holder.textView.text = num.id.toString()
holder.cardView.setTag(position)
holder.cardView.setOnClickListener(){
testAdapterCallback(num)
}
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val cardView = itemView.findViewById<CardView>(R.id.testCardView)
val textView = itemView.findViewById<TextView>(R.id.testTextView)
}
}
I have added second parametr into callback but i don't know how i must change my adapter's inicializations in this peace of code:
val adapter = TestAdapter(list) { item ->
testAdapterItemClick(item)
}
In activity i'm using this method :
private fun testAdapterItemClick(item: Test) {}
Please, help me to check the position of the choosen element. I need it later.
Thanks in advance)
P.S. Sorry for my English
Add the position as parameter in the callback.
So, instead of: private val testAdapterCallback: (Test)->Unit
Use: private val testAdapterCallback: (Test, Int)->Unit.
This way you can pass the position in the callback.
holder.cardView.setOnClickListener(){
testAdapterCallback(num, position)
}
In your activity:
val adapter = TestAdapter(list) { item, position ->
testAdapterItemClick(item)
}
Create interface for your OnClickListener
interface OnClickListener{
fun clickItem(test: Test, index: Int)
}
Pass listener to your adapter like below.
class TestAdapter(
var test : ArrayList<Test>?,
val clickListener: OnClickListener,
var mActivity: Activity
) :
RecyclerView.Adapter<TestAdapter.MyViewHolder>() {
}
Now in your onBindViewHolder add click listener.
var mtest= test !!.get(i)
holder.cardView.setOnClickListener {
clickListener.clickItem(mtest, i)
}
Implement Listener to your activity and initialize it.
this.mOnClickListener = this
Pass listener to your adapter where you passing the arraylist.
mTestAdapter = TestAdapter(arrayList, mOnClickListener ,mActivity)
You'll get the position in your activity override method.
override fun editItem(mTest: Test, index: Int) {
if (mTest!= null) {
}
}
Related
Please tell me how to transfer the ID (position) of the view element on recyclerview to another class?
class CardAdapter : RecyclerView.Adapter<CardAdapter.CardViewHolder>(), View.OnClickListener {
private var cardList = ArrayList<Card>()
private lateinit var card: Card
class CardViewHolder(
val binding: FragmentCardBinding
) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = FragmentCardBinding.inflate(inflater, parent, false)
return CardViewHolder(binding)
}
#SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
card = cardList[position]
..
}
override fun getItemCount(): Int = cardList.size
override fun onClick(v: View) {
when (v.id) {
R.id.root_card_template -> {
val intent = Intent(v.context, ProductActivity::class.java)
// need put id into ProductActivty
intent.putExtra("item", card.id)
v.context.startActivity(intent)
}
}
}
At the moment, it only passes the ID of the last generated element. For some reason there is almost no information on the Internet on this score
Just create an interface and implement that in the calling activity. While creating an instance of your adapter inside the activity, pass that interface along and on the click event of the view in the adapter class, call the interface's method with the data that you want to pass back to the activity.
interface OnItemClickListener{
fun onClick(pos: Int)
}
class YourActivity: AppCompatActivity(), OnItemClickListener {
override fun onStart() {
super.onStart()
//Create an instance of your adapter and pass the interface.
// Here #this context is being passed as Activity is implementing the interface.
val cardListAdapter = CardListAdapter(this)
}
override fun onClick(pos: Int) {
//Add your logic
}
}
// Then in your adapter class
class YourAdapter(private val itemClickListener: OnItemClickListener) :
RecyclerView.Adapter<CardListAdapter.CardViewHolder>() {
//Your code
override fun onBindViewHolder(holder: CardListAdapter.CardViewHolder, position: Int) {
yourView.setOnClickListener {
itemClickListener.onClick(position)
}
}
}
first you need to creat an interface
interface OnItemListener {
fun onItemSelect(position: Int)
}
then in your class that calls the recyclerview adapter, pass it to your recyclerView Adapter like this
var cardAdapter = CardAdapter(object :
OnItemListener {
override fun onItemSelect(position: Int) {
// you can handle your data here
// your position that you passed comes here
}
})
var layoutManager = GridLayoutManager(context, 2)
yourRecyclerViewId.adapter = cardAdapter
yourRecyclerViewId.layoutManager = layoutManager
finally in your adapter do like this
class CardAdapter(
private val onItemListener: OnItemListener
)
: RecyclerView.Adapter<CardAdapter.CardViewHolder>(), View.OnClickListener {
private var cardList = ArrayList<Card>()
private lateinit var card: Card
and in your on click event in the adapter call it as below:
onItemListener.onItemSelect(yourPosition)
i wanna ask something about my code.
so, I wanna retrieve the data that i have selected in the checkbox recyclerview, and then put it into variabel arraylist. and then when i click button next, i can use variabel arraylist in main code and then i can move to next page. can you help me to add that code on my coding?
anyway i use kotlin, so i need code kotlin
here my main coding
private fun getData() {
mDatabaseReference.addValueEventListener(object : ValueEventListener {
override fun onCancelled(databaseError: DatabaseError) {
Toast.makeText(this#ChooseCategoryActivity, ""+databaseError.message, Toast.LENGTH_SHORT).show()
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
dataCategory.clear()
for(getdataSnapshot in dataSnapshot.getChildren()) {
Log.i("dataKey", getdataSnapshot.key.toString())
val kategori = getdataSnapshot.getValue(Kategori::class.java)
dataCategory.add(kategori!!)
}
rv_user_kategori.adapter = UserCategoryAdapter(dataCategory) {
}
}
})
here my adapter recyclerview
class UserCategoryAdapter(private var data: List<Kategori>, private var listener: (Kategori) -> Unit) : RecyclerView.Adapter<UserCategoryAdapter.ViewHolder>() {
lateinit var ContextAdapter : Context
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
ContextAdapter = parent.context
val inflatedView = layoutInflater.inflate(R.layout.layout_row_kategori, parent, false)
return ViewHolder(inflatedView)
}
override fun getItemCount(): Int = data.size
override fun onBindViewHolder(holder: UserCategoryAdapter.ViewHolder, position: Int) {
holder.bindItem(data[position], listener,ContextAdapter, position)
}
class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
private val namaKategori:TextView = v.findViewById(R.id.txt_row_kategori)
var checkbox:CheckBox = v.findViewById(R.id.txt_row_kategori)
fun bindItem(data: Kategori, listener: (Kategori) -> Unit, context : Context, position : Int) {
namaKategori.text = data.nama
itemView.setOnClickListener {
listener(data)
}
}
}
}
please help me to find that solution.
Your listener currently return only the Kategori. Make it return also the position of the item on the list and/r the status of the checkbox. You can get the state of the checkbox with Checkbox.isChecked.
To use a listener you need to add invoke, so the flow should be :
Your adapter declaration
class UserCategoryAdapter(private var data: List<Kategori>, private var listener: (Kategori) -> Unit) : RecyclerView.Adapter<UserCategoryAdapter.ViewHolder>()
Then in your bind you send the listener via constructor as well
holder.bindItem(data[position], listener,ContextAdapter, position)
Once you are in the ViewHolder and you want to detect the state change listener you need to call it like
itemView.setOnClickListener { listener.invoke(data) }
What's the objective
Im currently working on an app which has a RecyclerView for the Settings menu. This menu serves to load other fragments. So i needed to implement an OnItemClick function: for this, i followed this video.
What's the probelm
Following the given tutorial, Android Studio flags val adapter = adapterSettings(settingsList), saying No value passed for parameter 'listener'. I suppose that im missing something, since without the code written in the tutorial, the RecyclerView works.
So, am i missing something? Are there any ways to fix this in an easy and clean way?
Code:
activitySettings.kt
class ndActSettings : AppCompatActivity(), adapterSettings.OnItemClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.ndactivity_settings)
topToolbarBack.setNavigationOnClickListener {
finish()
}
var settingsList = listOf(
dataItemsSettings(getString(R.string.look), getString(R.string.lookdescription), R.drawable.ic_colored_color_lens),
dataItemsSettings(getString(R.string.reproduction), getString(R.string.reproductiondescription), R.drawable.ic_colored_view_carousel),
dataItemsSettings(getString(R.string.images), getString(R.string.imagesdscription), R.drawable.ic_colored_image),
dataItemsSettings(getString(R.string.audio), getString(R.string.audiodescription), R.drawable.ic_colored_volume_up),
dataItemsSettings(getString(R.string.about), getString(R.string.aboutdescription), R.drawable.ic_colored_info)
)
val adapter = adapterSettings(settingsList) //ERROR HERE!
rvSettings.adapter = adapter
rvSettings.layoutManager = LinearLayoutManager(this)
}
override fun OnItemClick(position: Int) {
//TODO
}
}
adapterSettings.kt
class adapterSettings(
var settingsList: List<dataItemsSettings>,
var listener: OnItemClickListener
) : RecyclerView.Adapter<adapterSettings.SettingsViewHolder>() {
inner class SettingsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
init {
itemView.setOnClickListener(this)
}
override fun onClick(p0: View?) {
val position : Int = adapterPosition
if (position != RecyclerView.NO_POSITION) {
listener.OnItemClick(position)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingsViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_settings, parent, false)
return SettingsViewHolder(view)
}
override fun getItemCount(): Int {
return settingsList.size
}
override fun onBindViewHolder(holder: SettingsViewHolder, position: Int) {
holder.itemView.apply {
rvTitle.text = settingsList[position].stringTitle
rvDescription.text = settingsList[position].stringDescription
rvIcon.setImageResource(settingsList[position].itemIcon)
}
}
interface OnItemClickListener {
fun OnItemClick(position: Int)
}
}
The constructor of class adapterSettings is expecting two parameters
class adapterSettings(
var settingsList: List<dataItemsSettings>,
var listener: OnItemClickListener
)
However, you are instantiating the object with one parameter only:
val adapter = adapterSettings(settingsList)
So, you have to add a second parameter.. An object that implements OnItemClickListener. Since you activity already implements that interface, you can send the activity as second parameter:
val adapter = adapterSettings(settingsList, this)
I'm new to Android development (and Kotlin).
I'm trying to implement a RecyclerView (which works fine) and when I click on a specific row it opens a new activity (Intent).
However, whenever I've press/click on one of the rows, I'm only able to get the value "-1" returned.
I've tried a number of different approaches (you should see the number of tabs in my browser).
This seems like it should be a fairly straightforward occurrence for something as common as a RecyclerView, but for whatever reason I'm unable to get it working.
Here is my RecyclerView Adapter file:
class PNHLePlayerAdapter (val players : ArrayList<PNHLePlayer>, val context: Context) : RecyclerView.Adapter<ViewHolder>() {
var onItemClick: ((Int)->Unit) = {}
// Gets the number of items in the list
override fun getItemCount(): Int {
return players.size
}
// Inflates the item views
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(context).inflate(
R.layout.pnhle_list_item,
parent,
false
)
val viewHolder = ViewHolder(itemView)
itemView.setOnClickListener {
onItemClick(viewHolder.adapterPosition)
}
return ViewHolder(itemView)
}
// Binds each item in the ArrayList to a view
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.tvPlayerName?.text = players[position].Name
holder.tvPlayerRank?.text = position.toString()
holder.tvPNHLe?.text = players[position].PNHLe.toString()
holder.tvTeam?.text = players[position].Team
holder.ivLeague?.setImageResource(leagueImageID)
}
}
class ViewHolder (view: View) : RecyclerView.ViewHolder(view) {
val linLayout = view.hor1LinearLayout
val ivTeam = view.teamImageView
val tvPlayerName = view.playerNameTextView
val tvPlayerRank = view.rankNumTextView
val tvPNHLe = view.pnhleTextView
val tvTeam = view.teamTextView
val ivLeague = view.leagueImageView
}
As you can see, there is a class property "onItemClick" which uses a lambda as the click callback.
I setOnClickListener in the onCreateViewHolder method after the view is inflated.
Next, in my Activity I add the list to my Adapter and set the call back.
However, every time I 'Toast' the position it is displayed as '-1'.
val adapter = PNHLePlayerAdapter(list, this)
adapter.onItemClick = { position ->
Toast.makeText(this, position.toString(),Toast.LENGTH_SHORT).show()
var intent = Intent(this, PlayerCardActivity::class.java)
//startActivity(intent)
}
rv_player_list.adapter = adapter
Perhaps I'm not thinking about this properly, but shouldn't the position represent the row number of the item out of the RecyclerView???
Ideally, I need to use the position so that I can obtain the correct item from the 'list' (ArrayList) so that I can pass information to my next Activity using the Intent
I found the issue.
Change this line in onCreateViewHolder:
return ViewHolder(itemView)
to this one:
return viewHolder
I would reorganize the adapter like this:
class PNHLePlayerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<Adapter.ViewHolder>() {
interface AdapterListener {
fun onItemSelected(position: Int?)
}
var players: List<Player> = listOf()
set(value) {
field = value
this.notifyDataSetChanged()
}
var listener: AdapterListener? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_car_selector, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(position)
}
override fun getItemCount(): Int {
return brands.size
}
inner class ViewHolder(view: View): androidx.recyclerview.widget.RecyclerView.ViewHolder(view) {
private var position: Int? = null
private val baseView: LinearLayout? = view.findViewById(R.id.baseView) as LinearLayout?
...
init {
baseView?.setOnClickListener {
listener?.onManufacturerSelected(position)
}
}
fun bind(position: Int) {
this.position = position
...
}
}
}
And from your activity/fragment set the listener as adapter.listener = this, and implement the onItemSelected(position: Int?)
override fun onItemSelected(position: Int?) {
...
}
I am new on kotlin android. I have created the adapter for recyclerview. But I am not able to perform a click event for each recyclerview item. I need the explanation with the reference code.
Kindly help me to do this.
Thanks in advance.
Here is my code for your reference.
class CustomAdapter(val readerList: ReaderResponse, mainActivity:
MainActivity,val btnlistener: BtnClickListener) :
RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
companion object {
var mClickListener: BtnClickListener? = null
}
override fun onCreateViewHolder(viewgroup: ViewGroup, index: Int): ViewHolder
{
val view=LayoutInflater.from(viewgroup?.context).inflate(R.layout.reader_list,viewgroup,false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return readerList.results.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
mClickListener = btnlistener
val item = readerList
val reader:ReaderData = readerList.results[position]
/*p0?.imageview?.text=reader.readerIcon*/
holder?.reader_status?.text=reader.readerStatus
holder?.ward_name?.text=reader.wardName
holder?.reader_id?.text=reader.readerID
holder?.reader_name?.text=reader.readerName
holder?.reader_location?.text=reader.readerLocation
if (reader.readerStatus.toLowerCase().equals("yes")){
holder.reader_name.setTextColor(Color.parseColor("#24a314"))
}else if (reader.readerStatus.toLowerCase().equals("no")){
holder.reader_name.setTextColor(Color.parseColor("#f4312d"))
holder.warning.setVisibility(View.VISIBLE)
}
}
class ViewHolder(itemView: View) :RecyclerView.ViewHolder(itemView) {
val imageview = itemView.findViewById(R.id.imageview) as Button
val reader_name = itemView.findViewById(R.id.reader_name) as TextView
val reader_location = itemView.findViewById(R.id.floor_no) as TextView
val ward_name = itemView.findViewById(R.id.ward_name) as TextView
val reader_id = itemView.findViewById(R.id.reader_id) as TextView
val reader_status = itemView.findViewById(R.id.reader_status) as TextView
val warning=itemView.findViewById(R.id.warning) as Button
}
open interface BtnClickListener {
fun onBtnClick(position: Int)
}
}
You could use the following approach. This is taken from this blog by Antonio Leiva
Assuming your data class is ReaderData
class CustomAdapter(val readers: List, val listener: (ReaderData) -> Unit) {
/* Other methods */
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
/*...*/
holder.imageview.setOnClickListener {
listener(readers[position])
}
}
}
Now in your Activity or Fragment
recyclerview.adapter = CustomAdapter(readersList) { readerData ->
Log.i(TAG, "${readerData.readerID} clicked")
}
The idea is you pass a lambda which will be executed when your desired item is clicked.
You just need to implement BtnClickListener in the corresponding Activity in which this adapter is initialized. Once you have implemented the BtnClickListener it would override the function onBtnClick in the activity.
The only thing you need to do in the adapter is to initialize the onClickListener on the element you need and in that method just call imageview.setOnClickListener { mClickListener?.onBtnClick(position) }. It would send the position back in activity and you can perform your specific task there. For example I have implemented the ClickListener in one Activity and printed the log there it works fine. Below is the demo code for it.
class Main2Activity : AppCompatActivity(), CustomAdapter.BtnClickListener {
override fun onBtnClick(position: Int) {
Log.d("Position", position.toString())
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
val readerResponseList = ArrayList<YourModelClassName>()
val adapter = CustomAdapter(readerResponseList,this,this)
recyclerView.adapter = adapter
}
Hope it Helps.