How to set textView in a recyclerView at desired position - android

I have a recyclerView in which i have a list of items displayed in a LinearLayout.There is a "increase" button in every list which will increment a quantity by "1".But when I click the button on the first list item to increment the number..the incremented value is displayed in the last list item of the recyclerView not in the desired position where i clicked.Can anyone help me find the solution?
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
myholder = holder;
holder.item_name_text.setText(data.get(position).getName());
holder.item_price_text.setText(data.get(position).getPrice().toString());
holder.item_quantity_text.setText("500");
//Adding item to the cart
holder.add_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(totalItem>=0 && totalItem<10){
totalItem++;
myholder.item_totalquantity_text.setText(String.valueOf(totalItem));
}else{
Toast.makeText(myholder.itemView.getContext(),"Cannot add more item",Toast.LENGTH_SHORT).show();
}
}
});

So I always think of recyclerviews as the frontend that displays my data. If you would like to make changes to the actual data itself and make sure it gets reflected in the recyclerview, you will need to ensure the changes are made inside the arraylist of data objects.
You will need to add a field inside the data object and call it counter. Then you must increment the counter once the user clicks on the onClickListener.
myholder.item_totalquantity_text.setText(data.get(position).setCounter(data.get(position).getCounter())+1);

Do not set OnClickListener() in onBindViewHolder(). Instead do it in your ViewHolder class itself. And main ly as RecyclerView re-uses the holder objects to represent the new set of data that is becoming visible. So the listener on which yo click might be belonging to some other view holder so it appears there instead.
Have a quick read of this and this. These are not very relevant to you but it has info to understnad recycling concept so you can fix your stuff easily.

Related

RecyclerView list with RecyclerView items : How to refresh a specific item?

I am making a list with RecyclerView, let's call it VariationList.
VariationList will contains items (VariationsItem).
VariationsItems will contain a title, and a RecyclerView (VariationsItemsList).
If I click on an item of VariationsItemsList, I want the following VariationsItem to refresh, and eventually add or delete some of their items.
Is there any solution to refresh a specific item from the Adapter ?
Or do I need to delete all items, then add them after modification ?
I know it is pretty confusing, so here is an example of my model :
In red, this is the list of green items.
Each green item contains a title, and a blue list.
For example, if I click on "Petit", I want to refresh the "Test" list.
If I click on "Vert", I want to refresh the "Taille" list and the "Test" list, to eventually add some items, or delete some.
you can do it in onBindView holder in recycle view adapter
`` #Override
public void onBindViewHolder(Viewholder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//code what ever you want to change use position
}
});
});
or you can use https://github.com/greenrobot/EventBus for change any item from outside of activity

A single listener for multiple list items

I am using a RecyclerView for a list. Each layout item of the RecyclerView has a Button. This button is supposed to save some data(that which I bound to the view).
I thought that since the same button is in every view item, why not have a single static listener instance that I can bind to all the buttons. Because that would save some memory.
Now, a few points about the listener(View.OnClickListener()):
It is stored as a static member of my RecyclerView.Adapter class and gets instantiated once when the data is being bound for the first item.
The instance is created as an anonymous instance and inside a method( onBindViewHolder(ViewHolder, int position))
Inside the onClick(View v) method of the listener, I access the data to be bound. This data is retrieved from the list of data objects stored as Adapter source using position provided in this method( onBindViewHolder(ViewHolder, int position)).
Now, the problem:
When I click on button and check what item is going to be saved by the listener, I find that the first data entry in the RecyclerView is the one that gets saved corresponding to the clicks of any of the items of the RecyclerView.
I have no idea why this is happening. Can anybody find the cause of it?
Secondly, is this a good strategy to have a single listener for multiple list items?
Note: I am unable to post the code for it. Sorry about that.
The best way to handle RecyclerView clicks is like this:
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.list_item, parent, false);
final ViewHolder viewHolder = new ViewHolder(view);
viewHolder.actionButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int itemPosition = viewHolder.getAdapterPosition();
handleActionButtonClick(itemPosition);
}
});
return viewHolder;
}
It is simple and robust. Having single click listener for all the items is an extreme example of over optimisation. These few extra bytes will never matter and it will come with cost of extra boilerplate.
If you are getting the response based upon the first item of the Recyclerview, then to get the actual postion use getAdapterPosition() at ViewHolderclass or onBindView() and getTag() might as well help to get the exact data
Since RecyclerView(as its name suggest) recycles its child views, so there is no memory related issues.

How do I iterate through all the viewholders in a recyclerview adapter?

I have a fragment with a RecyclerView with some records databound to it. Each record is a product that is part of a "combo" special (bud light, miller light, tuna sandwich, etc.). Basically, the customer is selecting products for a combo (6 domestic beers, 2 sandwiches and 1 drink, etc.) Each product has a set of "product groupings" (domestic beer, beer, sandwich, lunch item, etc.). Next to each item I have a plus and minus button to add/subtract items into the shopping cart. Inside my adapter, I need to check if the customer has selected all of his "domestic beers" or both of his "sandwiches". if certain group quantity totals values are over the total number of that group allowed in the combo, I need to disable the add buttons for those items.
ComboItemsAdapter.java
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
...
itemHolder.tvQuantity.setText("0");
...
itemHolder.buy_subtract_button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v) {
...
checkTotals();
}
}
itemHolder.buy_add_button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v) {
...
checkTotals();
}
}
}
private void checkTotals(){
//here I want to check some stuff, and if that stuff is true I want to disable all the buttons in that viewholder, some buttons will be disabled, some won't
}
So my question is what is the best way to iterate through each row in my recyclerview/adapter in the checkTotals() function and disable the appropriate buttons?
Pass the itemHolder to the checkTotal() function and under that function, perform your condition statement to enable or disable the click.
Actually the Best place to check for a condition is inside onBindViewHolder itself!
Since you going to adjust UI of each row based on some condition, you have to do it in onBindViewHolder; since it is the method that get called when a row is recycled and going to be assigned new data..
P.S: However be aware that doing complex calculation inside onBindViewHolder is not advised as this method must executed as fast as possible, if your condition is a complex one please do it inside your adapter constructor and cache the result for each row.. Later just adjust your view inside onBindViewHolder based on the result.

Get all items from adapter (recyclerview) in Fragment

Hello I'm having an issue getting all of the items from my adapter in my fragment. To be more specific I am using a ScaleInAnimatorAdapter along with my Customer Adapter and when I attempt to get my checkbox items from the below posted code, within my Fragment, I only seem to get the visible items on screen.
private View.OnClickListener onAllClick = new View.OnClickListener() {
#Override public void onClick(View v) {
int count = listAdapter.getItemCount();
for (int i = 0; i < count; i++) {
View mChild = listTopics.getChildAt(i);
if( mChild != null ) {
Log.d(TAG,"getItemCount(): " + i );
CheckBox cBox = (CheckBox)mChild.findViewById(R.id.topic_chk);
cBox.setChecked(((CheckBox) v).isChecked());
Log.d(TAG,"isChecked" + cBox.getTag());
cBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(((CheckBox) v).isChecked()) {
checkboxAll.setChecked(false);
}
}
});
}
}
}
};
Essentially I am attempting to create a check all feature from the fragment, so that when this is clicked all of the checkbox items from the adapter are checked. I got that to work with the code I presented however the main issue is that I only get the items visible on the screen, so when I scroll to my other items they are not checked. Thus I am wondering if there is a better way or another way for me to get all of the items
Adapters are meant to bind underlying data stores to views; they generally shouldn't be used to store data themselves (except for having a copy of the data for view binding purposes) nor should they perform actions on data.
Instead, you should be modifying the underlying data, then updating the adapter through whatever mechanism you are already using. (Loaders, custom setters with notifyDataItemChanged, etc.).
Basically you can't. It'll be reusing the UI views.
You need to set a flag in all your data list objects, call notifyDataSetChanged() and onBindViewHolder check that flag and use it to check uncheck
if(listAdapter.getItem(position).getIsChecked())
viewHolder.checkBox.setChecked(true);
else
viewHolder.checkBox.setChecked(false);
Ok. Thank you all for those who have replied you helped me grasp something really basic and important that had alluded me.
I got it to work, so for anyone who might read this post, here is my solution:
Create necessary methods and field to update your data in a model (ie, private is_checked, set_checked(), is_checked(), etc)
In your adapter onBindViewHolder, you will set your holder checkbox to be associated to the data so something like:
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
obj.setSelected(buttonView.isChecked());
}
});
holder.checkBox.setChecked(obj.isSelected());
Then in your fragment or activity I just have a click listener on my main checkbox, and then when checked I loop through my data list, and using the model method I update my data and just simply use listAdapter.notifyDataSetChanged()
You are doing it wrongly.
You should update the adapter instead of updating the check box view.
What you can do , you can create a field in adapter data holder .
And whenever you change the selection,just update the field or multiple field and finally refresh the view.

How to save button state in RecyclerView after scrolling?

Inside onBindViewHolder I set a different state of a button by checking if id of that product is in a specific list:
ArrayList<String> compareProducts = CompareManager
.getProducts(context).getProducts();
if (compareProducts.contains(item.getId())) {
holder.compara.setText(context.getString(R.string.icon_checked));
}
But on scrolling, the checked buttons get messed up, by appearing in different locations. As I understand, when reusing the views, RecyclerView uses the wrong one. But why would that happen if I check by the ID of that product?
Update
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
// setting up other data from the view
// then change button if product was added in compare before (as mentioned before)
// then set button click listener
holder.compara.setOnClickListener(new View.OnClickListener() {
// change the button state
// and save the ID to CompareManager which saves data to SharedPreferences
//then set holder tag
holder.itemView.setTag(item);
Reset the view to it's default state before checking for item.getId() so if it was checked on the previous recycled view, it wouldn't re-use that and be reset to the default state.

Categories

Resources