How to Implement a View Holder

Android: Implementing ViewHolder

That's because a ViewHolder is not a class that is from the Android SDK, you make it yourself.
Based on what I can find, a ViewHolder is an implementation that stores Views (per row in a ListView usually) for a larger area, so it is a sort of helper class and cache mechanism. This is one example I found on Android Developers of what a ViewHolder would contain.

static class ViewHolder {
TextView text;
TextView timestamp;
ImageView icon;
ProgressBar progress;
int position;
}

Then you can implement it in a ListAdapter or a similar class.

How to use ViewBinding in a RecyclerView.Adapter?

What you need to do is pass the generated binding class object to the holder class constructor. In below example, I have row_payment XML file for RecyclerView item and the generated class is RowPaymentBinding so like this

    class PaymentAdapter(private val paymentList: List<PaymentBean>) : RecyclerView.Adapter<PaymentAdapter.PaymentHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PaymentHolder {
val itemBinding = RowPaymentBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return PaymentHolder(itemBinding)
}

override fun onBindViewHolder(holder: PaymentHolder, position: Int) {
val paymentBean: PaymentBean = paymentList[position]
holder.bind(paymentBean)
}

override fun getItemCount(): Int = paymentList.size

class PaymentHolder(private val itemBinding: RowPaymentBinding) : RecyclerView.ViewHolder(itemBinding.root) {
fun bind(paymentBean: PaymentBean) {
itemBinding.tvPaymentInvoiceNumber.text = paymentBean.invoiceNumber
itemBinding.tvPaymentAmount.text = paymentBean.totalAmount
}
}
}

Also, make sure you pass the root view to the parent class of Viewholder like this RecyclerView.ViewHolder(itemBinding.root) by accessing the passed binding class object.

How to implement a view holder?

You would need to write you own version of ListView to do that (which is bad). If the ListView doesn't work properly, it probably means that you are doing something wrong.

Where does the id element come from? You are getting the position in your getView() method, so you don't need to worry about exceeding list bounds. The position is linked to the element position in your list, so you can get the correct element like this:

myElements.get(position);

When the data in your list changes, you can call this:

yourAdapter.notifyDataSetChanged()

That will rebuild your list with new data (while keeping your scrolling and stuff).

How to implement a view holder?

You would need to write you own version of ListView to do that (which is bad). If the ListView doesn't work properly, it probably means that you are doing something wrong.

Where does the id element come from? You are getting the position in your getView() method, so you don't need to worry about exceeding list bounds. The position is linked to the element position in your list, so you can get the correct element like this:

myElements.get(position);

When the data in your list changes, you can call this:

yourAdapter.notifyDataSetChanged()

That will rebuild your list with new data (while keeping your scrolling and stuff).

how to start an activity from inner class view holder? [Android studio] [kotlin]

Firstly, you need to pass context as a parameter in your RecyclerAdapter. And, next thing you need to do is give an id to your root View of CardLayoutBinding. for e.g. here I supposed that your CardLayoutBinding XML looks something like this. So, I have provided id to the root view as 'itemViewContainer'

card_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<data>

</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/itemViewContainer"
android:layout_margin="10dp"
>

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/itemImage"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/itemImage"
android:id="@+id/itemTitle"
/>
</androidx.constraintlayout.widget.ConstraintLayout>

Now, in your adapter class you do the following changes:

RecyclerAdapter.java

class RecyclerAdapter(val context:Context) : RecyclerView.Adapter<...>(){
.......
.....

inner class ViewHolder(val binding: ItemLayoutBinding): RecyclerView.ViewHolder(binding.root){}
.......
......

override fun onBindViewHolder(holder: RecyclerAdapter.ViewHolder, position: Int) {
with(holder){
with(binding){
itemImage.setImageResource(image[position])
itemTitle.text = titles[position]

//from here you can click on item to start new Activity and pass position.you can also use intent to pass position either.
itemViewContainer.setOnClickListener {
val bundle = Bundle()
bundle.putInt("position", position)
context.startActivity(Intent(context, YourDesiredActivity::class.java).putExtras(bundle))
}
}
}
}
.......
.......

}

Can I make a recyclerview without an xml layout for the ViewHolder?

Yes. onCreateViewHolder just returns a ViewHolder with a ViewGroup (possibly even just a View) as the root view.

Your problem is that you added it to a parent. You don't want to do that. The RecyclerView will end up being its parent. You should just be creating it and returning a holder with that view as the root view.

Yes, even though the parent passed in is probably (although not necessarily) also the RecyclerView. The layout manager of the recycler view does the adding. That's why the last parameter of your inflate() call is false- to prevent inflate from adding it to a parent.



Related Topics



Leave a reply



Submit