Hide and show item when the user click on it using adapter - android

My list is about questions and answer.
I've designed an item that has the question and answer and I'm planing to hide and show the answer, not the whole item (GONE/VISIBLE), when the user click on the question. So it will be more like expandable way.
Now this is my adapter:
class FaqExpandableAdapter internal constructor(private val context: Context, private var items: List<Faq>,private val callBack: AdapterCallBack?) : RecyclerView.Adapter<FaqExpandableAdapter.MyViewHolder>() {
private val inflater: LayoutInflater = LayoutInflater.from(context)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = inflater.inflate(R.layout.item_question_faq, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.txtQuestionFaq.text = items[position].question?.toString() ?: "-"
holder.txtAnswerFaq.text = items[position].answer?.toString() ?: "-"
}
override fun getItemCount(): Int {
return items.size
}
fun update(items: List<Faq>) {
this.items = items
notifyDataSetChanged()
}
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
#BindView(R.id.txtQuestionFaq)
lateinit var txtQuestionFaq: AppCompatTextView
#BindView(R.id.txtAnswerFaq)
lateinit var txtAnswerFaq: AppCompatTextView
init {
ButterKnife.bind(this, itemView)
}
#OnClick(R.id.relativeRowFaq)
fun onItemClicked() {
callBack?.onItemClicked(adapterPosition)
}
}
interface AdapterCallBack {
fun onItemClicked(position: Int)
}
}
My last step is where to do the visibility action?

Kotlin : Write onClick method on your onBindViewHolder function.
holder.txtQuestionFaq.setOnClickListener {
holder.txtAnswerFaq.visibility = View.VISIBLE;
}

In onBindViewHolder() method, add below lines: (I use Java)
holder.txtQuestionFaq.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.txtAnswerFaq.setVisibility(View.VISIBLE);
}
});

Related

How to implement two OnClickListener on two different views on RecyclerView kotlin?

I am working a RecyclerView item that has two views in it: a TextView and an ImagaView. I want to be able to click on both of them to cary out different functionalities.
How can I go about this
Here is my Adapter
class AddMeasurementAdapter(private val currentList:MutableList<DressMeasurementModel>, private val listener1: RecyclerClickListener, private val listener2: RecyclerClickListener): RecyclerView.Adapter<AddMeasurementAdapter.CardViewHolder>() {
//inner class
inner class CardViewHolder (itemView : View):RecyclerView.ViewHolder(itemView), View.OnClickListener{
val display:TextView = itemView.findViewById(R.id.measurement_recyclerview_item)
//Binding the data with the view
fun bind(dressMeasurementModel: DressMeasurementModel){
display.text = "${dressMeasurementModel.measurementName} ${dressMeasurementModel.measurement}"
}
init {
itemView.setOnClickListener(this#CardViewHolder)
}
override fun onClick(v: View?) {
val position: Int = adapterPosition
if (position != RecyclerView.NO_POSITION) {
listener1.onItemClick1(position, currentList)
}
if (position != RecyclerView.NO_POSITION) {
listener2.onItemClick2(position, currentList)
}
}
}
//Creating view
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.measurement_fragment_recyclerview_items, parent, false)
return CardViewHolder(view)
}
//Binding the view
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
holder.bind(currentList[position])
}
//Getting the item cout size
override fun getItemCount(): Int {
return currentList.size
}
}
Here is my interface
interface RecyclerClickListener {
fun onItemClick1(position: Int, currentList: MutableList<DressMeasurementModel>)
fun onItemClick2(position: Int, currentList: MutableList<DressMeasurementModel>)
}
You can add a listener in createViewHolder such as
//Creating view
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.measurement_fragment_recyclerview_items, parent, false)
view.textView.onClick{}
view.image.onClick{}
return CardViewHolder(view)
}
Okay, here is the Kotlin version of the answer.
In your bind method of viewholder,
fun bind(dressMeasurementModel: DressMeasurementModel) {
...
var position = adapterPosition
display.setOnClickListener {
listener.onTextClick(position)
}
image.setOnClickListener {
listener.onImageClick(position)
}
...
}
I later figured it So i want to share how i did it.
class AddMeasurementAdapter(
private val currentList: MutableList<DressMeasurementModel>,
private val listener1: RecyclerClickListener,
private val listener2: RecyclerClickListener
) : RecyclerView.Adapter<AddMeasurementAdapter.CardViewHolder>() {
// inner class
inner class CardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val display: TextView = itemView.findViewById(R.id.measurement_recyclerview_item)
val delete: ImageView = itemView.findViewById(R.id.measurementment_recyclerview_item_delete_button)
// Binding the data with the view
fun bind(dressMeasurementModel: DressMeasurementModel) {
display.text = "${dressMeasurementModel.measurementName} ${dressMeasurementModel.measurement}"
}
}
// Creating view
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
val view = LayoutInflater.from(parent.context).inflate(
R.layout.measurement_fragment_recyclerview_items,
parent,
false
)
return CardViewHolder(view)
}
// Binding the view and attaching the listener
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
holder.bind(currentList[position])
holder.display.setOnClickListener {
listener1.onItemClickToEdit(holder.adapterPosition, currentList)
}
holder.delete.setOnClickListener {
listener2.onItemClickToDelete(holder.adapterPosition, currentList)
}
}
// Getting the item cout size
override fun getItemCount(): Int {
return currentList.size
}
}
When i assigned the onClickListener inside the fun bind(), the listener covered the the whole itemView layout and not the individual view inside the layout, hence only one click listener was achieved. The same thing applied inside the inner class.
Here is the interface
interface RecyclerClickListener {
fun onItemClickToEdit(position: Int, currentList: MutableList<DressMeasurementModel>)
fun onItemClickToDelete(position: Int, currentList: MutableList<DressMeasurementModel>)
}
By extending the interface in either activity of fragment, you have your onclickListener.
This article helped https://antonioleiva.com/recyclerview-listener/

Android: Values are not assigned when using data binding in my custom adapter

I'm trying to pass my binding variable for the adapter to the ViewHolder to assing values to the textviews in my adapter but the values are not assigned and the click listeners dont do anything.
Here's my adapter class:
class DoneAppointmentsAdapter(var context: DoneAppointmentsFragment, listener: ContentListener, var arrayList: List<Appointment>) :
RecyclerView.Adapter<DoneAppointmentsAdapter.ItemHolder>() {
private val listener: ContentListener = listener
private var binding: DoneAppointmentsAdapterBinding? = null
var activity = context
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ItemHolder {
val viewHolder = LayoutInflater.from(parent.context)
.inflate(R.layout.done_appointments_adapter, parent, false)
binding = DoneAppointmentsAdapterBinding.inflate(LayoutInflater.from(parent.context))
return ItemHolder(viewHolder,binding, parent.context)
}
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
holder.bind(arrayList, listener)
}
override fun getItemCount(): Int {
return arrayList.size
}
class ItemHolder(view: View, var binding: DoneAppointmentsAdapterBinding?, val context: Context) : RecyclerView.ViewHolder(view) {
fun bind(listOfData: List<Appointment>, listener: ContentListener) {
val dataListItem = listOfData[adapterPosition]
binding?.donePatientItemName?.text = "${dataListItem.patientName}"
binding?.donePatientItemTime?.text = "Some date"
binding?.donePatientItemPatientInfo?.setOnClickListener {
tempAppointmentId = dataListItem.id
listener.onPatientHistoryViewClicked(dataListItem.requestedBy)
}
binding?.donePatientItemReviewCase?.setOnClickListener {
amendPrescriptionWarning(dataListItem,context)
}
binding.donePatientItemViewCase.setOnClickListener {
startPreview(dataListItem)
}
}
}
}
You have messed up inside onCreateViewHolder . you have created view twice once with the LayoutInflater.from(parent.context) and once with DoneAppointmentsAdapterBinding.inflate . There should be only one in this case onlyDoneAppointmentsAdapterBinding .
class DoneAppointmentsAdapter(var context: DoneAppointmentsFragment, listener: ContentListener, var arrayList: List<Appointment>) :
RecyclerView.Adapter<DoneAppointmentsAdapter.ItemHolder>() {
private val listener: ContentListener = listener
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ItemHolder {
val binding = DoneAppointmentsAdapterBinding.inflate(LayoutInflater.from(parent.context))
return ItemHolder(binding)
}
override fun onBindViewHolder(holder: ItemHolder, position: Int) {
holder.bind(arrayList, listener)
}
override fun getItemCount(): Int {
return arrayList.size
}
class ItemHolder (var binding: DoneAppointmentsAdapterBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(listOfData: List<Appointment>, listener: ContentListener) {
val dataListItem = listOfData[adapterPosition]
binding.donePatientItemName.text = "${dataListItem.patientName}"
binding.donePatientItemTime.text = "Some date"
binding.donePatientItemPatientInfo.setOnClickListener {
tempAppointmentId = dataListItem.id
listener.onPatientHistoryViewClicked(dataListItem.requestedBy)
}
binding.donePatientItemReviewCase.setOnClickListener {
amendPrescriptionWarning(dataListItem,binding.donePatientItemReviewCase.context)
}
binding.donePatientItemViewCase.setOnClickListener {
startPreview(dataListItem)
}
}
}
}
It should be like this . I have also removed extra useless arguments from ItemHolder .
To make it clear the problem with your code was RecyclerView.ViewHolder(view) you were passing view while you were doing all action and stuff on binding those holds are two different instances of View . Which should be fixed with above code.

How Can I create Interface for ItemClickListener in Kotlin?

I am new to Android & Kotlin. I want to click my row and intent it to other activity. That's why I tried to create an interface in my Adapter but it does not work. How can I create it?
My adapter code:
class NoteAdapter(private val titleTextArray: ArrayList<String>, private val imageArray: ArrayList<String>) : RecyclerView.Adapter<NoteAdapter.NoteHolder>() {
class NoteHolder (view: View) : RecyclerView.ViewHolder(view) {
var recyclerTitleText: TextView ?= null
var recyclerImageView: ImageView ?= null
init {
recyclerTitleText = view.findViewById(R.id.recyclerTitleText)
recyclerImageView = view.findViewById(R.id.recyclerImage)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.recycler_row, parent, false)
return NoteHolder(view)
}
override fun onBindViewHolder(holder: NoteHolder, position: Int) {
holder.recyclerTitleText?.text = titleTextArray[position]
Picasso.get().load(imageArray[position]).into(holder.recyclerImageView)
}
override fun getItemCount(): Int {
return titleTextArray.size
}
}
With Kotlin, you could to use a lambda (higher order function) to fetch the user clicks in the holder. For example, a base approach could be the next:
class YourAdapter(
private val listener: (String) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val yourDataList = emptyList<String>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.compound_checkbox_terms_layout, parent, false)
return YourViewHolder(view)
}
override fun getItemCount(): Int {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
private inner class YourViewHolder(view: View) : RecyclerView.ViewHolder(view) {
init {
if (adapterPosition != RecyclerView.NO_POSITION) {
val selectedData = yourDataList[adapterPosition]
listener.invoke(selectedData)
}
}
}
}
Pass the activity context to the adapter from Activity so it can launch intent
Activity Code :
mAdapter = new CustomAdapter(this, imageArray, ArrayList);
Adapter Code :
class NoteAdapter(private val titleTextArray: ArrayList, private val imageArray: ArrayList, private val context : Context) : RecyclerView.Adapter<NoteAdapter.NoteHolder>() {
class NoteHolder (view: View) : RecyclerView.ViewHolder(view) {
var recyclerTitleText: TextView?= null
var recyclerImageView : ImageView?= null
init {
recyclerTitleText = view.findViewById(R.id.recyclerTitleText)
recyclerImageView = view.findViewById(R.id.recyclerImage)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.recycler_row, parent, false)
return NoteHolder(view)
}
override fun onBindViewHolder(holder: NoteHolder, position: Int) {
holder.recyclerTitleText?.text = titleTextArray[position]
Picasso.get().load(imageArray[position]).into(holder.recyclerImageView)
holder.recyclerImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, NesneTani.class);
context.startActivity(intent);
}
});
}
override fun getItemCount(): Int {
return titleTextArray.size
}
}
Create an Interface to catch the click event. (position is optional)
interface OnItemClickListener {
fun onItemClick(position: Int)
}
add OnItemClickListener as a parameter in your Adapter class
class NoteAdapter(
private val titleTextArray: ArrayList<String>,
private val imageArray: ArrayList<String>,
private val listener: OnItemClickListener
) : RecyclerView.Adapter<NoteAdapter.NoteHolder>()
Then do below inside onBindViewHolder
override fun onBindViewHolder(holder: NoteHolder, position: Int) {
listener.onItemClick(position)
}
now inside your activity, implement the OnItemClickListener
class ActivityName implements OnItemClickListener{}
and while initiating adapter, do this
mAdapter = new CustomAdapter(this, imageArray, ArrayList);
Then inside the overridden method do what you want
override fun onItemClick(position: Int) {
//start the activity you want.
}

I'm using a RecyclerView, how to add Intent to it?

I am using a RecyclerView and I want to add a click listener to it. How can I achieve this? Here's my Adapter class for reference.
class ItemAdapter(var context:Context, var list:ArrayList<Items>): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
var v:View=LayoutInflater.from(context).inflate(R.layout.item_row,parent,false)
return ItemHolder(v)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as ItemHolder).bind(list[position].name,list[position].price,list[position].picture,list[position].id)
}
class ItemHolder(itemView: View): RecyclerView.ViewHolder(itemView){
fun bind(n:String,p:Double,u:String,item_id:Int)
{
itemView.item_name.text=n
itemView.item_price.text=p.toString()+" "+"USD"
var web:String=("http://192.168.0.101/web%20Sales/images/"+u)
web=web.replace(" ","%20")
//Picasso.with(itemView.context).load(web).into(itemView.item_photo)
Glide.with(itemView.context).load(web).into(itemView.item_photo).toString()
itemView.item_add_photo.setOnClickListener{
UserInfo.itemId=item_id
var obj= QtyFragment()
var manager=(itemView.context as Activity).fragmentManager
obj.show(manager, "Qty")
}
itemView.det_btn.onItem
}
}
}
If you want to set Click Listener to an item in RecyclerView, you can do that from your ItemHolder class -
class ItemHolder(itemView: View): RecyclerView.ViewHolder(itemView){
var currentItem: Items? = null
var currentPosition: Int = 0
init{
itemView.item_add_photo.setOnClickListener {
currentItem?.let {
val message: String = "My item is: " + currentItem!!.name
val intent = Intent(context, YourActivity::class.java)
context.startActivity(intent)
}
}
}
fun bind(n:String,p:Double,u:String,item_id:Int)......
}
In the Adapter:
class ItemHolder(itemView: View): RecyclerView.ViewHolder(itemView){
...
init {
itemView.setOnClickListener{
onItemClick?.invoke(list[adapterPosition])
}
}
...
In the Activity or Fragment where you setup the Adapter:
adapter.onItemClick = { item ->
//do something
))
Try this way.on clicking on itemView...
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//enter code here
}
});

How to implement onItemClick and onLongItemClick in RecycleView for Kotlin in android

I have used Kotlin for implementing click listeners
How to properly use it, currently click is not detecting, I am not able to detect click using below code.
class AdptEvents (val items: MutableList<TestModel>, val context: Context) : RecyclerView.Adapter<ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.row_event, parent, false))
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder?.tvAnimalType?.text = items.get(position).getName()
holder?.rootView.setOnClickListener{
clickEventRow(items,position)
true
}
holder?.rootView.setOnLongClickListener {
clickEventRow(items,position)
true
}
}
private fun clickEventRow( items: MutableList<TestModel>, position: Int ) {
Toast.makeText(context,items[position].getName(),Toast.LENGTH_LONG).show()
}
}
class ViewHolder (view: View) : RecyclerView.ViewHolder(view) {
// Holds the TextView that will add each animal to
val tvAnimalType = view.txtTitle!!
val rootView = view.eventListRootId!!
}
You dont need anything else
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder?.tvAnimalType?.text = items.get(position).getName()
holder?.rootView.setOnClickListener{
// code here
}
holder?.rootView.setOnLongClickListener {
//code here
}
}
Change your view holder. Also, if you need to get index, use adapterPosition variable.
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
// Holds the TextView that will add each animal to
val tvAnimalType = itemView.txtTitle!!
val rootView = itemView.eventListRootId!!
init {
itemView.setOnClickListener {
Toast.makeText(context, "OnClick", Toast.LENGTH_LONG).show()
}
// OnLongClick and etc.
}
}
If you need to handle root view click events apply it dirrectly
class ViewHolder (view: View) : RecyclerView.ViewHolder(view) {
// Holds the TextView that will add each animal to
val tvAnimalType = view.txtTitle!!
view.setOnClickListener {
Toast.makeText(view.context, "OnClick", Toast.LENGTH_LONG).show()
}
view.setOnLongClickListener {
Toast.makeText(view.context, "OnLongClick", Toast.LENGTH_LONG).show()
true
}
}

Categories

Resources