I forgot how to check a single checkbox in a recyclerview. I looked at how to have single choice on checkbox in recyclerview? but you shouldn't need to call notifyDataSetChanged. I tried this and the wrong checkbox is being selected:
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.tps.challenge.R
import com.tps.challenge.domain.Store
import com.tps.challenge.ui.Event
class StoreFeedAdapter(
private val stores: List<Store>,
private val itemClickListener: (Event<Store>) -> Unit
): RecyclerView.Adapter<StoreItemViewHolder>() {
private var prevSelectedPos: Int = 0
private var currSelectedPos: Int = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StoreItemViewHolder {
return StoreItemViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_store, parent, false)
).also { viewHolder ->
viewHolder.storeImage.setOnClickListener {
val selectedStore = stores[viewHolder.adapterPosition]
itemClickListener.invoke(
Event(selectedStore)
)
}
viewHolder.checkbox.setOnClickListener {
currSelectedPos = viewHolder.adapterPosition
notifyItemChanged(prevSelectedPos)
notifyItemChanged(currSelectedPos)
prevSelectedPos = currSelectedPos
}
}
}
override fun onBindViewHolder(holder: StoreItemViewHolder, position: Int) {
holder.checkbox.isSelected = currSelectedPos == position
val store = stores[position]
with(holder.itemView) {
findViewById<TextView>(R.id.name).text = store.name
findViewById<TextView>(R.id.description).text = store.desc
Glide.with(holder.itemView.context)
.load(store.coverImgUrl)
.into(holder.storeImage)
}
}
override fun getItemCount(): Int {
return stores.size
}
}
class StoreItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val storeImage: ImageView = itemView.findViewById(R.id.iv_store)
val checkbox: CheckBox = itemView.findViewById(R.id.cb_select)
}
class StoreFeedAdapter(
private val stores: List<Store>,
private val itemClickListener: (Event<Store>) -> Unit
): RecyclerView.Adapter<StoreItemViewHolder>() {
private var prevSelectedPos: Int = 0
private var currSelectedPos: Int = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StoreItemViewHolder {
return StoreItemViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_store, parent, false)
).also { viewHolder ->
viewHolder.storeImage.setOnClickListener {
val selectedStore = stores[viewHolder.adapterPosition]
itemClickListener.invoke(
Event(selectedStore)
)
}
viewHolder.checkbox.setOnClickListener {
currSelectedPos = viewHolder.adapterPosition
notifyDataSetChanged()
}
}
}
override fun onBindViewHolder(holder: StoreItemViewHolder, position: Int) {
if(currSelectedPos == position){checked}else{unChecked}
val store = stores[position]
with(holder.itemView) {
findViewById<TextView>(R.id.name).text = store.name
findViewById<TextView>(R.id.description).text = store.desc
Glide.with(holder.itemView.context)
.load(store.coverImgUrl)
.into(holder.storeImage)
}
}
override fun getItemCount(): Int {
return stores.size
}
}
class StoreItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val storeImage: ImageView = itemView.findViewById(R.id.iv_store)
val checkbox: CheckBox = itemView.findViewById(R.id.cb_select)
}
Related
I was wondering how I add binding to my viewholder so I am able to get the todoTitle and cbDone variables or find an alternative way to get these variables. I have already tried researching this however, I could not put binding into the viewholder's parameters since it will only allow one (itemview: View) so if theres any alternative way to use binding or get these parameters then that will be very helpful.
Any help would be greatly appreciated.
If you need any more code then please ask.
Main Activity
package com.example.todoit
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.todoit.data.Todo
import com.example.todoit.data.TodoDataBase
import com.example.todoit.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var todoAdapter: TodoAdapter
private lateinit var todoDB: TodoDataBase
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
todoAdapter = TodoAdapter(mutableListOf())
val rvTodoItems = binding.rvTodoItems
val btnAddTodo = binding.btnAddTodo
val etTodoTitle = binding.etTodoTitle
val btnDeleteTodo = binding.btnDeleteTodo
rvTodoItems.layoutManager = LinearLayoutManager(this)
rvTodoItems.adapter = todoAdapter
btnAddTodo.setOnClickListener {
val todoTitle = binding.etTodoTitle.toString()
if (todoTitle.isNotEmpty()) {
val todo = Todo(null, todoTitle, false)
todoAdapter.addTodo(todo)
etTodoTitle.text.clear()
Toast.makeText(this, "Successfully written data", Toast.LENGTH_LONG).show()
writeData()
} else {
Toast.makeText(this, "There was an error while writing data", Toast.LENGTH_LONG)
.show()
}
}
btnDeleteTodo.setOnClickListener {
todoAdapter.deleteDoneTodos()
Toast.makeText(this, "Selected Todo(s) Deleted", Toast.LENGTH_LONG).show()
}
}
private fun writeData() {
val todoTitle = binding.etTodoTitle.toString()
if (todoTitle.isNotEmpty()) {
val todo = Todo(null, todoTitle, false)
//Add data to database
todoDB.todoDao().insertAll(todo)
}
}
}
TodoAdapter
package com.example.todoit
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.todoit.data.Todo
class TodoAdapter(
private val todos: MutableList<Todo>,
) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
return TodoViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_todo,
parent,
false
)
)
}
fun addTodo(todo: Todo) {
todos.add(todo)
notifyItemInserted(todos.size - 1)
}
fun deleteDoneTodos() {
todos.removeAll { todo ->
todo.isChecked
}
notifyDataSetChanged()
}
private fun toggleStrikeThrough(tvTodoTitle: TextView, isChecked: Boolean) {
if(isChecked) {
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags or STRIKE_THRU_TEXT_FLAG
} else {
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
}
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val curTodo = todos[position]
holder.itemView.apply {
etTodoTitle = curTodo.title
cbDone.isChecked = curTodo.isChecked
toggleStrikeThrough(tvTodoTitle, curTodo.isChecked)
cbDone.setOnCheckedChangeListener { _, isChecked ->
toggleStrikeThrough(tvTodoTitle, isChecked)
curTodo.isChecked = !curTodo.isChecked
}
}
}
override fun getItemCount(): Int {
return todos.size
}
}
Here is a sample adapter, this adapter is working well. You can use it
public class SenListAdapter() :
RecyclerView.Adapter<SenListAdapter.MyViewHolder>() {
var data: MutableList<QuizResponse.Datum> = ArrayList()
var itemListener: EventListener? = null
var inflater: LayoutInflater? = null
private var onLoadMoreListener: OnLoadMoreListener? = null
var mData = ""
var context:Context?=null
constructor(context: Context, quizType: String) : this() {
this.quizType = quizType
this.context=context
}
override fun getItemViewType(position: Int): Int {
return position
}
fun addAll(mData: List<QuizResponse.Datum>?) {
data.clear();
data.addAll(mData!!)
notifyDataSetChanged()
}
fun clear() {
data.clear()
notifyDataSetChanged()
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): SenListAdapter.MyViewHolder {
inflater = LayoutInflater.from(parent.context)
val itemHomeSenBinding = DataBindingUtil.inflate<ItemHomeSenBinding>(
inflater!!,
R.layout.item_home_sen, parent, false
)
return MyViewHolder(itemHomeSenBinding)
}
override fun onBindViewHolder(holder: SenListAdapter.MyViewHolder, position: Int) {
populateItemRows(holder, position)
}
private fun populateItemRows(holder: SenListAdapter.MyViewHolder, position: Int) {
var item = data.get(position)
holder.itemHomeSenBinding.tvQuizName.text = item.name
holder.itemHomeSenBinding.tvCost.text = "₹ " + item.entryFee.toString()
holder.itemHomeSenBinding.tvEstimatedTime.text = item.time
holder.itemHomeSenBinding.tvWinningAmtText.text = "Win upto ₹ " + item.reward.toString()
}
override fun getItemCount(): Int {
return data.size
}
inner class MyViewHolder(var itemHomeSenBinding: ItemHomeSenBinding) :
RecyclerView.ViewHolder(
itemHomeSenBinding.root
) {
init {
setEventlistener(itemListener)
}
}
interface EventListener {
fun onBuyNow(position: Int, item: QuizResponse.Datum?)
fun onStartNow(position: Int, item: QuizResponse.Datum?)
}
fun setEventlistener(onItemClick: EventListener?) {
itemListener = onItemClick
}
}
I have a recycler view made up for rows. Each row has a button and an image. I want to add an onClick listener on each image. How can I do that using android and kotlin? I know how to add an onClick listener on the row but not on the elements of the row?
Here's my code
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import com.sumizeit.sumizeit.*
import kotlinx.android.synthetic.main.activity_home.*
class HomeAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
private var context: Context
private var list: ArrayList<HomeRow>
constructor(context: Context, list: ArrayList<HomeRow>){
this.context = context
this.list = list
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val vHolder = holder as YourViewHolder
Picasso.get().load(list[position].image1).into(vHolder.txtImage1);
Picasso.get().load(list[position].image2).into(vHolder.txtImage2);
Picasso.get().load(list[position].image3).into(vHolder.txtImage3);
Picasso.get().load(list[position].image4).into(vHolder.txtImage4);
Picasso.get().load(list[position].image5).into(vHolder.txtImage5);
vHolder.txtImage1.setOnClickListener {
//TODO something..
Intent(context, BookDetailActivity::class.java).apply {
putExtra("bookId", list[position].id1)
}
}
vHolder.txtImage2.setOnClickListener {
//TODO something..
Intent(context, BookDetailActivity::class.java).apply {
putExtra("bookId", list[position].id2)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.home_row, parent, false)
return YourViewHolder(view)
}
override fun getItemCount(): Int {
return list.size
}
var onItemClick: ((pos: Int, view: View) -> Unit)? = null
inner class YourViewHolder(itemView: View): RecyclerView.ViewHolder(itemView), View.OnClickListener {
override fun onClick(v: View) {
onItemClick?.invoke(adapterPosition, v)
}
val txtImage1 = itemView.findViewById<ImageView>(R.id.imageView1)
val txtImage2 = itemView.findViewById<ImageView>(R.id.imageView2)
val txtImage3 = itemView.findViewById<ImageView>(R.id.imageView3)
val txtImage4 = itemView.findViewById<ImageView>(R.id.imageView4)
val txtImage5 = itemView.findViewById<ImageView>(R.id.imageView5)
init {
itemView.setOnClickListener(this)
}
}
}
in Activity
var adp = HomeAdapter(this, listHomeRow);
rv.adapter = adp
change your code
override fun onClick(v: View) {
onItemClick?.invoke(adapterPosition, v)
}
val txtImage1 = itemView.findViewById<ImageView>(R.id.imageView1)
val txtImage2 = itemView.findViewById<ImageView>(R.id.imageView2)
val txtImage3 = itemView.findViewById<ImageView>(R.id.imageView3)
val txtImage4 = itemView.findViewById<ImageView>(R.id.imageView4)
val txtImage5 = itemView.findViewById<ImageView>(R.id.imageView5)
init {
itemView.setOnClickListener(this)
}
}
to
inner class YourViewHolder(itemView: View): RecyclerView.ViewHolder(itemView), View.OnClickListener {
override fun onClick(v: View) {
onItemClick?.invoke(adapterPosition, v)
}
val txtImage1 = itemView.findViewById<ImageView>(R.id.imageView1)
val txtImage2 = itemView.findViewById<ImageView>(R.id.imageView2)
val txtImage3 = itemView.findViewById<ImageView>(R.id.imageView3)
val txtImage4 = itemView.findViewById<ImageView>(R.id.imageView4)
val txtImage5 = itemView.findViewById<ImageView>(R.id.imageView5)
init {
txtImage1.setOnClickListener{
Intent(context, BookDetailActivity::class.java).apply {
putExtra("bookId", list[layoutPosition].id1)
context.startActivity(this)
}
}
txtImage2.setOnClickListener{
Intent(context, BookDetailActivity::class.java).apply {
putExtra("bookId", list[layoutPosition].id2)
context.startActivity(this)
}
}
}
}
and remove clickListener in your bindViewHolder() method. try this bro.
In anticipation of your adapter, I made some sample code.
class CategoryAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
private var context: Context
private var list: ArrayList<YourItem>
constructor(context: Context, list: ArrayList<YourItem>){
this.context = context
this.list = list
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.your_layout, parent, false)
YourViewHolder(view)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val cameraViewHolder = holder as YourViewHolder
cameraViewHolder.imageView.setOnClickListener {
//TODO something..
Intent(context, MainActivity::class.java).apply {
putExtra("category", list[position].name)
}
}
}
internal class YourViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val imageView: ImageView = itemView.your_image
}
}
New, Try this
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import com.sumizeit.sumizeit.*
import kotlinx.android.synthetic.main.activity_home.*
import kotlinx.android.synthetic.main.home_row.*
class HomeAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
private var context: Context
private var list: ArrayList<HomeRow>
constructor(context: Context, list: ArrayList<HomeRow>){
this.context = context
this.list = list
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val vHolder = holder as YourViewHolder
with(Picasso.get()){
load(list[position].image1).into(vHolder.txtImage1)
load(list[position].image2).into(vHolder.txtImage2)
load(list[position].image3).into(vHolder.txtImage3)
load(list[position].image4).into(vHolder.txtImage4)
load(list[position].image5).into(vHolder.txtImage5)
}
vHolder.txtImage1.setOnClickListener {
//TODO something..
Intent(context, BookDetailActivity::class.java).apply {
putExtra("bookId", list[position].id1)
context.startActivity(this)
}
}
vHolder.txtImage2.setOnClickListener {
//TODO something..
Intent(context, BookDetailActivity::class.java).apply {
putExtra("bookId", list[position].id2)
context.startActivity(this)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.home_row, parent, false)
return YourViewHolder(view)
}
override fun getItemCount(): Int {
return list.size
}
inner class YourViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val txtImage1 = itemView.imageView1
val txtImage2 = itemView.imageView2
val txtImage3 = itemView.imageView3
val txtImage4 = itemView.imageView4
val txtImage5 = itemView.imageView5
}
}
Inside the adapter where the ImageView is bound. Just use that reference to set the onClickListener. You're probably doing it inside the onBindViewHolder method or inside the ViewHolder.
Create a Custom view for the recycler view :
<androidx.cardview.widget.CardView
android:id="#+id/info_card_view"
app:cardCornerRadius="#dimen/dimen_card_radius"
app:cardElevation="#dimen/dimen_card_elevation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/dimen_common_margin">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/list_item_constraintlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/dimen_card_padding">
...
<!--Image corresponding to info-->
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/image_pexel"
android:layout_width="#dimen/dimen_0"
android:layout_height="wrap_content"
android:contentDescription="#null"
android:layout_margin="#dimen/dimen_common_margin"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:imageUrl="#{pexelPhoto.src.medium}"
app:layout_constraintEnd_toEndOf="parent"
tools:srcCompat="#drawable/ic_launcher_foreground"/>
...
</androidx.constraintlayout.widget.ConstraintLayout>
Create a custom viewholder which will have click listener for the image in recyclerview row :
class PhotosViewHolder(private val viewBinding: ViewDataBinding) :
RecyclerView.ViewHolder(viewBinding.root) {
fun bind(data: Any, listener: OnItemClickListener) {
viewBinding.setVariable(BR.pexelPhoto, data)
(viewBinding.root.findViewById(R.id.image_pexel) as ImageView).setOnClickListener { _ ->
listener.onThumbnailClick(data as PexelPhoto)
}
viewBinding.executePendingBindings()
}
}
You can check the complete source here for reference : https://github.com/spartan-1/PexelsApp
I want to create a new intent/activity when the user clicks on a cardview respectively and i was wondering how does one do it in kotlin. i noticed most tutorials are in java and i'm a student who did not learn java.
package com.example.ttshfypj.adapters
import androidx.fragment.app.Fragment
import android.view.View
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.ttshfypj.data_class.medications
import android.widget.ImageView
import android.widget.TextView
import com.example.ttshfypj.R
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.list_medication.view.*
class medicationAdapter (val medicationlist: ArrayList<medications>) : RecyclerView.Adapter<medicationAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_medication, parent, false)
return ViewHolder(v)
}
override fun getItemCount(): Int {
return medicationlist.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val medicationgroup: medications = medicationlist[position]
holder?.medicationnamevar?.text = medicationgroup.medicineN
holder?.medicationschedulevar?.text = medicationgroup.MedicineTime
val imagemedicine = holder?.itemView?.medicationimageview
Picasso.get().load(medicationgroup.MedicineImage).into(imagemedicine)
}
class ViewHolder(itemView: View) :RecyclerView.ViewHolder(itemView) {
val medicationnamevar = itemView.findViewById(R.id.medicationname) as TextView
val medicationschedulevar = itemView.findViewById(R.id.medicationschedule) as TextView
}
}
If you are using kotlin you can also use method reference where you directly pass a method to be called inside the adapter and you can directly invoke it there.
Activity.kt
Adapter(this::itemClickHandler);
private fun itemClickHandler(int position){
// your logic here
}
Adapter.kt
class Adapater(val itemClickHandler:(Int)->Unit):RecyclerView.Adapter(){
override fun onBindViewHolder(){
//you can invoke it here like this
itemClickHandler.invoke(adapterPosition);
}
}
please refer this full code
MainActivity.kt
package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val list = mutableListOf<Items>()
for(i in 1..25){
list.add(Items(CHILD,"Child"))
}
with(rvList) {
layoutManager = LinearLayoutManager(this#MainActivity)
adapter = Adapter(list, this#MainActivity::onItemClickHandler)
}
}
private fun onItemClickHandler(position:Int){
Log.d("***","${position}");
//here you can start a new intent to open a new activity on click of item
}
}
The adapter code is as following
package com.example.myapplication
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.layout_child.view.*
import kotlinx.android.synthetic.main.layout_header.view.*
const val HEADER = 1;
const val CHILD = 2;
data class Items(val type: Int, val text: String)
class Adapter(private val list: List<Items>, val itemClickHandler: (Int) -> Unit) :
RecyclerView.Adapter<Adapter.HeaderViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
val headerView =
LayoutInflater.from(parent.context).inflate(R.layout.layout_header, parent, false)
val headerViewHolder = HeaderViewHolder(headerView)
headerView.setOnClickListener {
itemClickHandler.invoke(headerViewHolder.adapterPosition)
}
return headerViewHolder
}
override fun getItemCount(): Int = list.size
override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
holder.onBind(list[position].text)
}
inner class HeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun onBind(text: String) {
itemView.tvHeader.text = text
}
}
}
Hope this helps and you are able to follow
You can create an interface for Item Click Listener like
interface MyItemClickListener{
fun itemClick(position: Int)
}
Now you should pass context to the constructor of your adapter.
class medicationAdapter (val medicationlist: ArrayList<medications>, var context: Context) : RecyclerView.Adapter<medicationAdapter.ViewHolder>() {...}
and create an instance of MyItemClickListener inside your adapter
// create instance of MyItemClickListener
private val clickListener = context as MyItemClickListener
And setclick listener on your view inside the onCreateViewHolder.
modify your adapter like this
class medicationAdapter (val medicationlist: ArrayList<medications>, var context: Context) : RecyclerView.Adapter<medicationAdapter.ViewHolder>() {
// create instance of MyItemClickListener
private val clickListener = context as MyItemClickListener
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
var inflater = LayoutInflater.from(parent.context)
var v = inflater.inflate(R.layout.list_medication, parent, false)
var viewHolder = ViewHolder(v)
// here you set click listener on your item view.
v.setOnClickListener {
clickListener.itemClick(viewHolder.adapterPosition)
}
return viewHolder
}
override fun getItemCount(): Int {
return medicationlist.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val medicationgroup: medications = medicationlist[position]
holder?.medicationnamevar?.text = medicationgroup.medicineN
holder?.medicationschedulevar?.text = medicationgroup.MedicineTime
val imagemedicine = holder?.itemView?.medicationimageview
Picasso.get().load(medicationgroup.MedicineImage).into(imagemedicine)
}
class ViewHolder(itemView: View) :RecyclerView.ViewHolder(itemView) {
val medicationnamevar = itemView.findViewById(R.id.medicationname) as TextView
val medicationschedulevar = itemView.findViewById(R.id.medicationschedule) as TextView
}
}
And finally, in your activity, you have to implement the MyItemClickListener interface and override the itemClick() like this
class YourActivity: AppCompatActivity(), MyItemClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// ....
}
override fun itemClick(position: Int) {
Log.d("TAG","Click Item Position: "+position)
// here you can call your new activity according to your item position.
}
}
As you know, you can create RecyclerView with multiple ViewHolders follow step:
getItemViewType()
onCreateViewHolder()
onBindViewHolder()
But i can only create two viewholder in other row, example:
I have a list (item 1 - type 1, item 2 - type 1, item 3 - type 2)
So when i use GridLayoutManager with span column is 2, item-1 and item-2 is same row because it same type,
**I have another list (item 1 - type 1, item 2 - type 3, item 3 - type 2)
**
They will be arranged 3 three rows, so i want combine item1 and item 2 same row, not combine layout. Can anyone have an idea?
package info.androidhive.recyclerview
import android.annotation.TargetApi
import android.content.Context
import android.content.res.Configuration
import android.os.Build
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
class MoviesAdapter(private val moviesList: List<Movie>) : RecyclerView.Adapter<MoviesAdapter.ViewHolder>() {
var pos = true
fun notifyLayoutChanged(context: Context) {
val isLanscape = context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
convert(moviesList, isLanscape)
notifyDataSetChanged()
}
#TargetApi(Build.VERSION_CODES.N)
private fun convert(moviesList: List<Movie>, isLanscape: Boolean) {
if (isLanscape) {
moviesList.forEach {
if (it.type == Movie.Type.PICKUP) {
it.type = Movie.Type.BANNER
}
}
}
}
class MyViewHolder(view: View) : ViewHolder(view) {
var title: TextView
var year: TextView? = null
var genre: TextView
init {
title = view.findViewById<View>(R.id.title) as TextView
genre = view.findViewById<View>(R.id.genre) as TextView
}
override fun bind(movie: Movie) {
title.text = movie.title
genre.text = movie.genre
}
companion object {
fun create(context: Context): MyViewHolder {
return MyViewHolder(LayoutInflater.from(context)
.inflate(R.layout.movie_list_row, null, false))
}
}
}
class BannerViewHolder(view: View) : ViewHolder(view) {
var view1: MovieView
var view2: MovieView
init {
view1 = view.findViewById<View>(R.id.item1) as MovieView
view2 = view.findViewById<View>(R.id.item2) as MovieView
}
override fun bind(movie: Movie) {
view1.bind(movie)
view2.bind(movie)
}
companion object {
fun create(context: Context): BannerViewHolder {
return BannerViewHolder(LayoutInflater.from(context)
.inflate(R.layout.banner, null, false))
}
}
}
abstract class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
abstract fun bind(movie: Movie)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
if (viewType == Movie.Type.BANNER.ordinal) {
if (pos) {
pos = false
return MyViewHolder.create(parent.context)
} else {
pos = true
return BannerViewHolder.create(parent.context)
}
} else {
return MyViewHolder.create(parent.context)
}
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView?) {
super.onDetachedFromRecyclerView(recyclerView)
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
if (holder != null) {
val movie = moviesList[position]
holder.bind(movie)
}
}
fun getItem(position: Int): Movie {
return moviesList[position]
}
override fun getItemViewType(position: Int): Int {
val movie = moviesList[position]
return movie.type.ordinal
}
override fun getItemCount(): Int {
return moviesList.size
}
}
I want to implement onClickListener on recyclerview item. Here is my CustomAdapter.kt Code.
package com.png.kotlinsample
/**
* Created by admin on 13-08-2017.
*/
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
/**
* Created by prashant on 6/19/2017.
*/
class CustomAdapter(val userList: ArrayList<User>, val listener: (User) -> Unit) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
//this method is returning the view for each item in the list
class MyAdapter(val userList: ArrayList<User>)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false)
return ViewHolder(v)
}
//this method is binding the data on the list
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.bindItems(userList[position],listener)
}
//this method is giving the size of the list
override fun getItemCount(): Int {
return userList.size
}
//the class is hodling the list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(user: User, listener: (User) -> Unit) = with(itemView) {
val textViewName = itemView.findViewById(R.id.textViewUsername) as TextView
val textViewAddress = itemView.findViewById(R.id.textViewAddress) as TextView
textViewName.text = user.name
textViewAddress.text = user.address
setOnClickListener { listener(user) }
}
}
}
I want the click listener callback from my activity.
class CustomAdapter(
val userList: List<User>,
val listener: (User) -> Unit
) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder = ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false))
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.bindItems(userList[position])
}
override fun getItemCount(): Int = userList.size
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textViewName: TextView = itemView.findViewById(R.id.textViewUsername)
private val textViewAddress: TextView = itemView.findViewById(R.id.textViewAddress)
fun bindItems(user: User) = with(itemView) {
textViewName.text = user.name
textViewAddress.text = user.address
setOnClickListener { listener(user) }
}
}
}
Then
val adapter = CustomAdapter(userList) { user ->
// do something with user on click
}
recyclerView.adapter = adapter
Ok let's do it in 3 steps
1- You define a interface with onClick method to be your callbacks
like this
interface UserClickCallbacks {
fun onUserClick(user: User)
}
2- Second in your adapter you add a click listener in the view holder with call the interface method like this
EDIT
class CustomAdapter(val userList: ArrayList<User>, private val userClickCallbacks: UserClickCallbacks) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
//this method is returning the view for each item in the list
class MyAdapter(val userList: ArrayList<User>)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false)
return ViewHolder(v)
}
//this method is binding the data on the list
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.textViewName.text = user.name
holder.textViewAddress.text = user.address
}
//this method is giving the size of the list
override fun getItemCount(): Int {
return userList.size
}
//the class is hodling the list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
init {
view.setOnClickListener(this)
}
val textViewName = itemView.findViewById(R.id.textViewUsername)
val textViewAddress = itemView.findViewById(R.id.textViewAddress)
override fun onClick(p0: View?) {
userClickCallbacks.onUserClick(userList[adapterPosition])
}
}
}
3- At your activity you implement the the UserClickCallbacks interface
and override the onUserClick() method like this
class UserActivity : AppCompatActivity(), UserClickCallbacks {
// your activity code
override fun onUserClick(user: User) {
// but the user click event logic here
// This triggered when user in tha adapter clicked
}
}
Don't forget to add inner to ViewHolder class or else you won't get access to listener object which is inside Adapter :
package com.niel.customview
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
/**
* Created by nileshdeokar on 12/03/2018.
*/
class MediaAdapter(private var mData: ArrayList<String>) : RecyclerView.Adapter<MediaAdapter.ViewHolder>() {
lateinit var listener: OnItemClickedListener
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent?.context)
.inflate(R.layout.row_media, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
val model = mData[position]
}
override fun getItemCount(): Int {
return mData.size
}
inner class ViewHolder : RecyclerView.ViewHolder, View.OnClickListener {
var imageViewSq: ImageView
constructor(itemView: View?) : super(itemView) {
imageViewSq = itemView?.findViewById(R.id.imgSq)!!
itemView.setOnClickListener(this)
}
override fun onClick(p0: View?) {
listener.onItemClick(adapterPosition)
}
}
fun setOnItemClickedListener(listener: OnItemClickedListener) {
this.listener = listener
}
interface OnItemClickedListener {
fun onItemClick(position: Int)
}
}