I use following function to animate filtering a list (actually I once found that somewhere, don't know where anymore):
public void animateTo(List<T> items) {
applyAndAnimateRemovals(items);
applyAndAnimateAdditions(items);
applyAndAnimateMovedItems(items);
}
private void applyAndAnimateRemovals(List<T> newItems) {
for (int i = mListItems.size() - 1; i >= 0; i--) {
final T item = mListItems.get(i);
if (!newItems.contains(item)) {
removeItem(i);
}
}
}
private void applyAndAnimateAdditions(List<T> newItems) {
for (int i = 0, count = newItems.size(); i < count; i++) {
final T item = newItems.get(i);
if (!mListItems.contains(item)) {
addItem(i, item);
}
}
}
private void applyAndAnimateMovedItems(List<T> newItems) {
for (int toPosition = newItems.size() - 1; toPosition >= 0; toPosition--) {
final T item = newItems.get(toPosition);
final int fromPosition = mListItems.indexOf(item);
if (fromPosition >= 0 && fromPosition != toPosition) {
moveItem(fromPosition, toPosition);
}
}
}
public T removeItem(int position) {
final T item = mListItems.remove(position);
notifyItemRemoved(position);
return item;
}
public void addItem(int position, T item) {
mListItems.add(position, item); // <- EXCEPTION IS THROWN HERE
notifyItemInserted(position);
}
public void moveItem(int fromPosition, int toPosition) {
final T model = mListItems.remove(fromPosition);
mListItems.add(toPosition, model);
notifyItemMoved(fromPosition, toPosition);
}
Sometimes I get an exception like following in the addItem function:
java.lang.IndexOutOfBoundsException: Invalid index 203, size is 201
Actually, how can this happen? The loop in applyAndAnimateAdditions begins at 0, adds items one by one if they are not already in the list. How can the index exception occur?
You can add this to check if the position is equal or larger(>=) to the ArrayLists size just add the item to the end of the Arraylist.
public void addItem(int position, T item) {
if(position >= mListItems.size())
mListItems.add(mListItems.size()-1, item);
else
mListItems.add(position, item);
notifyItemInserted(position);
}
So here's your problem you are iterating through newItems but you are adding to mListItems
Related
My title is my problem, I have 3 pages in a viewPager. How do I redirect to first page when I swipe on the last page in viewPager?
ViewPager.OnPageChangeListener viewPagerPageChangeListener = new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
int x = position;
Log.i("ON Possition",Integer.Tostring(x));
if(x == 3){
viewPager.setCurrentItem(x);
Log.i("ON last Possition",Integer.Tostring());
}
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
};
you can't move to first page smoothly from last page.
read below code. we should fake item count.
private class MyPagerAdapter extends PagerAdapter {
Context context;
public MyPagerAdapter(Context context) {
this.context= context;
}
#Override
public int getCount() {
if (tList != null && tList.size() > 1) {
return tList.size() * MAX_PAGE; // simulate infinite by big number of products
} else {
return tList.size();
}
}
#Override
public int getItemPosition(Object object) {
int position;
if (tList != null && tList.size() > 1) {
position = super.getItemPosition(object) % tList.size(); // use modulo for infinite cycling
return position;
} else {
return super.getItemPosition(object);
}
}
public int getItemPosition(int index) {
int position;
if (tList!= null && tList.size() > 1) {
position = index % tList.size(); // use modulo for infinite cycling
return position;
} else {
return index;
}
}
}
I have an ArrayList<Model> type and having fields id,name,isSelected and I have one HashMap which can store only selected items means if the item is clicked it will be stored in HashMap<Intere,Model>, Integer will be id , Model is that object which can be selected. I want to update Arraylist item field isSeleted to true which is present in hashmap. How can i do? I have tried many condition but nothing is working fine.
ArrayList<MainInterestModel> mainInterestList;
public static HashMap<Integer, MainInterestModel> mainIntrestHash = new HashMap<>();
Iterator myVeryOwnIterator = mainIntrestHash.keySet().iterator();
while (myVeryOwnIterator.hasNext()) {
int key = (int) myVeryOwnIterator.next();
MainInterestModel value = (MainInterestModel) mainIntrestHash.get(key);
int id = value.getId();
for (int i = 0; i < mainInterestList.size(); i++) {
MainInterestModel model = mainInterestList.get(i);
if (model.getId() == id) {
model.setSelected(true);
mainInterestList.set(i, model);
} else {
model.setSelected(false);
mainInterestList.set(i, model);
}
}
}
By Default isSelected is false but when the user will click that item will be stored in HashMap later i want to update selection so user interface will show selected items. HashMap has selected items and arraylist have all items but isSelected are false. at the time of showing selected items, I'm taking isSelected is true or not, which working fine, but arraylist update is not working.
My adapter class code
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final MainInterestModel mainInterestModel = mainInterestModels.get(position);
holder.tvName.setText(mainInterestModel.getName());
holder.ivMainInterest.setImageResource(mainInterestModel.getImage());
// here isSelected is always false because in activity infalting adpter with arraylist, i want to setSeletced by hash object
boolean isSelected = mainInterestModel.isSelected();
if (isSelected) {
holder.ivMainInterest.setImageResource(R.drawable.bath_selector);
Log.e("Is Item selected ::", "" + mainInterestModel.getId());
} else {
holder.ivMainInterest.setImageResource(R.drawable.ic_bath);
Log.e("Is Item deselected ::", "" + mainInterestModel.getId());
}
holder.ivMainInterest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean selection = mainInterestModel.isSelected();
if (selection) {
holder.ivMainInterest.setImageResource(R.drawable.ic_bath);
mainInterestModel.setSelected(false);
mainIntrestHash.remove(mainInterestModel.getId());
Log.e("After Remove SIZE:---", "" + mainIntrestHash.size());
} else {
mainInterestModel.setSelected(true);
holder.ivMainInterest.setImageResource(R.drawable.bath_selector);
mainIntrestHash.put(mainInterestModel.getId(), mainInterestModel);
Log.e("After Adding SIZE:---", "" + mainIntrestHash.size());
}
}
});
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
holder.ivMainInterest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean selection = mainInterestModel.isSelected();
if (selection) {
holder.ivMainInterest.setImageResource(R.drawable.ic_bath);
mainInterestModel.setSelected(false);
} else {
mainInterestModel.setSelected(true);
holder.ivMainInterest.setImageResource(R.drawable.bath_selector);
}
notifyDataSetChanged();
}
});
}
remove hashmap and try to use this.
use this
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class ModelIterator {
public static void main(String arg[]) {
ArrayList<mainModel> mainmoldelList = new ArrayList<mainModel>();
for (int i = 1; i <= 3; i++) {
mainModel m = new mainModel();
m.setId(i);
m.setName("Rajendra" + i);
m.setSelected(false);
mainmoldelList.add(m);
}
mainModel m = new mainModel();
m.setId(0);
m.setName("Rajendra0");
m.setSelected(false);
HashMap<Integer, mainModel> mMap = new HashMap<Integer, mainModel>();
mMap.put(1, m);
Iterator<Entry<Integer, mainModel>> ite = mMap.entrySet().iterator();
while (ite.hasNext()) {
Map.Entry<Integer, mainModel> pair = (Map.Entry<Integer, mainModel>) ite
.next();
int key = pair.getKey();
mainModel mObj = (mainModel) mMap.get(key);
for (int i = 0; i < mainmoldelList.size(); i++) {
if (mainmoldelList.get(i).id == key) {
mainModel tmp = new mainModel();
tmp.setId(mainmoldelList.get(i).id);
tmp.setName(mainmoldelList.get(i).name);
tmp.setSelected(true);
mainmoldelList.add(tmp);
mainmoldelList.remove(i);
}
}
}
for (int i = 0; i < mainmoldelList.size(); i++) {
System.out.println(mainmoldelList.get(i).id + " "
+ mainmoldelList.get(i).name + " "
+ mainmoldelList.get(i).isSelected);
}
}
}
I'm getting this error when i'm implementing footer within recycler view.
This is how i have done it. I was using two types for showing different views in list, but something is not set well in method getItemCount() or maybe when i'm getting position of clicked item model in list.
This is what i have so far:
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_FOOTER = 1;
#Override
public int getItemCount() {
return mUsers == null ? 0 : mUsers.size() + 1;
}
#Override
public int getItemViewType(int position) {
if (isFooterPosition(position)) {
return VIEW_TYPE_FOOTER;
}
return VIEW_TYPE_ITEM;
}
private boolean isFooterPosition(int position) {
return position == mUsers.size() + 1;
}
private User getUser (int position) {
return mUsers.get(position - 1); // Here i'm getting an error mentioned in title
}
Edit:
if (holder instanceof UserHolder) {
final User user = getUser(position);
UserHolder userViewHolder = (UserHolder) holder;
userViewHolder.tvUserName.setText(user.getName());
userViewHolder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(v, position);
}
});
} else if (holder instanceof FooterViewHolder) {
FooterViewHolder footerViewHolder = (FooterViewHolder) holder;
Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "Lato-Thin.ttf");
footerViewHolder.mButton.setTypeface(typeface);
}
I have some items for normal holder view in list and one item for footer view.
mUsers.get(position - 1); will crash when the position is 0 because you're looking for the item at index -1 which is invalid.
If you're adding a footer, which will be present after all of the previous items, then do you need do the substraction?
Position 0 => User 0
Position 1 => User 1
Position N => User N
Position N + 1 => Footer
It might be better to just return mUsers.get(position).
Edit: There's another small issue:
Here's an issue:
private boolean isFooterPosition(int position) {
return position == mUsers.size() + 1;
}
mUsers.size() is 20, so users will have positions 0-19.
isFooterPosition should return true for 20 (users size + 1). However, that will return false because the footer is at position 21.
Thus, you have a spot (20) that is completely invalid.
private boolean isFooterPosition(int position) {
return position == mUsers.size();
}
I think you can modify getUser() method like following:
private boolean isValidPos(int position){
return position >= 0 && position < mUsers.size();
}
private User getUser (int position) {
if (isFooterPosition(position)) return null;
return isValidPos(position) ? mUsers.get(position) : null;
}
I can't see exactly what you want to do, but, as someone said before me, the error is in mUsers.get(position - 1);, because it's gonna search for a negative index if position == 0.
So, if you really need the subtraction, you can do like this:
private User getUser (int position) {
if(position != 0)
return mUsers.get(position - 1);
else
return mUsers.get(position);
}
But, as you can see, for position == 0, it will return the same output as position == 1.
I have found a solution and i have also extended RecyclerView with one more typeview for showing one view where there is no item:
First i have declared these variables in my adapter:
public static final int COUNT_FOOTER = 1;
public static final int COUNT_NO_ITEMS = 1;
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_FOOTER = 1;
private final int VIEW_TYPE_NO_ITEM = 2;
After that i have define three view types for my list:
#Override
public int getItemViewType(int position) {
if (!mUsers.isEmpty()) {
if (position < mUsers.size()) {
return VIEW_TYPE_ITEM;
} else {
return VIEW_TYPE_FOOTER;
}
} else {
if (position == 0) {
return VIEW_TYPE_NO_ITEM;
} else {
return VIEW_TYPE_FOOTER;
}
}
}
#Override
public int getItemCount() {
if (!mUsers.isEmpty()) {
return mUsers.size() + COUNT_FOOTER;
} else {
return COUNT_NO_ITEMS + COUNT_FOOTER;
}
}
private User getUser (int position) {
return mUsers.get(position);
}
İ have a problem about RecyclerView filter.
İ am using edittext on text change method for filter text query in recyclerview but when i filter my Product List is changing.
Note : all of that in fragment and fragment in viewpager.
My problem is that : when i write something it is working but at the same time my product list's elements are changing to result of filter.
So in example at first
MyList Has 40 items
FilteredDataList is empty
After i write "a" in edittext after that FilteredDataList is has 30 items but MyList has same 30 items. But i have not set anything to Mylist
My Data List ,i get it from sqlite
productList = new ArrayList<>();
productList = handler.getAllProduct();
My Filter Method
private List<Product> filter(List<Product> models, String query) {
query = query.toLowerCase();
List<Product> filteredModelList = new ArrayList<>();
filteredModelList.clear();
for (Product model : models) {
final String text = model.get_ProductName().toLowerCase();
if (text.contains(query)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
My Edittext OnChange Metod
searchEdt.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (s.length() != 0) {
List<Product> filteredModelList = filter( productList, s.toString());
rcAdapter.animateTo(filteredModelList);
pager_recycler_view.scrollToPosition(0);
} else {
rcAdapter.animateTo(productList);
pager_recycler_view.scrollToPosition(0);
}
}
});
My AdapterClass
public class ProductRecyclerViewAdapter extends RecyclerView.Adapter< ProductRecyclerViewHolder > {
private List<Product> itemList;
private Context context;
public ProductRecyclerViewAdapter(Context context, List<Product> itemList) {
this.itemList = itemList;
this.context = context;
}
#Override
public ProductRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_card_single_item, null);
ProductRecyclerViewHolder rcv = new ProductRecyclerViewHolder(layoutView);
return rcv;
}
#Override
public void onBindViewHolder(ProductRecyclerViewHolder holder, int position) {
holder.productName.setText(itemList.get(position).get_ProductName());
holder.productWatCode.setText("%" +itemList.get(position).get_ProductWatCode());
holder.productPOR.setText("%" +itemList.get(position).get_ProductPOR());
holder.productRSP.setText("£" +itemList.get(position).get_ProductRSP());
holder.productDescription.setText(itemList.get(position).get_ProductDescription());
holder.productSKU.setText(itemList.get(position).get_ProductSKU());
holder.productPrice.setText("£" + itemList.get(position).get_ProductPrice());
// holder.productCountCart.setText("");
Picasso.with(context)
.load( "http://firmabayi.com/images/ilanK/" +itemList.get(position).get_ProductPhoto())
.placeholder(R.drawable.add_icon)
.error(R.drawable.minus_icon)
.into(holder.productPhoto);
// holder.countryPhoto.setImageResource(itemList.get(position).get_ProductName());
}
#Override
public int getItemCount() {
return this.itemList.size();
}
public void animateTo(List<Product> itemList) {
applyAndAnimateRemovals(itemList);
applyAndAnimateAdditions(itemList);
applyAndAnimateMovedItems(itemList);
}
private void applyAndAnimateRemovals(List<Product> newModels) {
for (int i = itemList.size() - 1; i >= 0; i--) {
final Product model = itemList.get(i);
if (!newModels.contains(model)) {
removeItem(i);
}
}
}
private void applyAndAnimateAdditions(List<Product> newModels) {
for (int i = 0, count = newModels.size(); i < count; i++) {
final Product model = newModels.get(i);
if (!itemList.contains(model)) {
addItem(i, model);
}
}
}
private void applyAndAnimateMovedItems(List<Product> newModels) {
for (int toPosition = newModels.size() - 1; toPosition >= 0; toPosition--) {
final Product model = newModels.get(toPosition);
final int fromPosition = itemList.indexOf(model);
if (fromPosition >= 0 && fromPosition != toPosition) {
moveItem(fromPosition, toPosition);
}
}
}
public Product removeItem(int position) {
final Product model = itemList.remove(position);
notifyItemRemoved(position);
return model;
}
public void addItem(int position, Product model) {
itemList.add(position, model);
notifyItemInserted(position);
}
public void moveItem(int fromPosition, int toPosition) {
final Product model = itemList.remove(fromPosition);
itemList.add(toPosition, model);
notifyItemMoved(fromPosition, toPosition);
}
}
i solved my problem it is only about adapter class one line :(
in adapter class
instead of
this.itemList = itemList;
use that
this.itemList = new ArrayList<>(itemList);
It is about your productList.
When you create a object like doing this;
Class a = b();
You are cloning your object. In deep, they are the same object.
So when you filtered object named a, b is being effected from this.
In short, don't do this. Instead of cloning object you should add each items to a from b by one by.
Like this;
productList = new ArrayList<>();
for( int i = 0 ; i <arrayFromSource.size() ; i++ )
{
productList.add(arrayFromSource.get(i));
}
I have an inventory class that has an array of the class 'Item', called items. Within the Item class, I have an int called quantity to represent how many of the item that you get with each pickup. I haven't been able to figure out how to get the number of duplicate items within the array, so that I can multiply that by the getQuantity() method for that item and get the total quantity of the item that the player is carrying.
public class Inventory {
private Item[] items; //A private Item array, called items
private int firstFree;
private int quantity;
private WorldRenderer world;
/**
* CREATES THE INVENTORY AT A SIZE SPECIFIED IN THE PARATHENESIS
*/
public Inventory(int size) {
items = new Item[size];
firstFree = 0;
}
public int getItemCount() {
for (int i = firstFree; i < items.length; i++) {
if (items[i] != null) {
return items.length;
}
}
return 0;
}
public boolean add(Item item) {
if (firstFree == items.length) {
return false;
}
items[firstFree] = item;
for (int i = firstFree; i < items.length; i++)
if (items[i] == null) {
firstFree = i;
return true;
}
firstFree = items.length;
return true;
/**for (int i = 0; i < items.length; i++)
if (items[i] == null){
items[i] = item;
System.out.println("Item " + item.getName() + " added to inventory at index " + i); // TESTING
return true;
}
return false;
}**/
}
public Item get(int index) {
return items[index];
}
public void setQuantity(Item item, int quantity) {
for (int i = 0; i < items.length; i++) {
if (items[i] == item) {
items[i].setQuantity(quantity);
}
}
}
public void removeQuantity(Item item, int quantity) {
for (int i = 0; i < items.length; i++) {
if (items[i] == item) {
items[i].setQuantity(item.getQuantity() - quantity);
}
}
}
public int getQuantity(Item item) {
int quantity = 0;
for (int i = 0; i < items.length; i++) {
if (items[i] == item) {
quantity = items[i].getQuantity();
}
}
return quantity;
}
}
Perhaps there is a better way to go about creating an inventory for my particular problem?
EDIT:
Trying the HashMap and getting an NPE at this line
if (items.containsKey(item)){
Integer previousQuantity = items.get(items);
items.put(item, ++previousQuantity); // NPE this line.
} else {
items.put(item, 1);
}
Rather than Item[] items you might consider HashMap<Item, Integer> items where the Integer refers to quantity.
This would make sure that there are no duplicate Items as well as simplify finding the quantity.
Example:
import java.util.HashMap;
public class Inventory {
private HashMap<Item, Integer> items;
private int maxSize;
public Inventory(int maxSize) {
this.maxSize = maxSize;
items = new HashMap<Item, Integer>();
}
public int getItemCount() {
int count = 0;
for (Item item: items.keySet()){
count += items.get(item);
}
return count;
}
public boolean add(Item item) {
if (items.size() >= maxSize){
return false;
}
if (items.containsKey(item)){
Integer previousQuantity = items.get(items);
items.put(item, ++previousQuantity);
} else {
items.put(item, 1);
}
return true;
}
}
Generic Implementation of equals() and hashCode():
public class Item {
int itemType;
#Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
Item item = (Item) o;
if (itemType != item.itemType) { return false; }
return true;
}
#Override
public int hashCode() {
return itemType;
}
}
you can find out number of unique item by using Set. In Set no item is repeated. So if you can convert your array to set then you can find the number of unique item. And you can get the number of repeated item by subtracting from the total item.
to convet array to Set you have to do
Set<Integer> uniqueItem = new HashSet<Integer>(Arrays.asList(items));
int total_repeated_item=items.length-uniqueItem.size();
You probably need a unique ID to differentiate between items in you inventory, you can then put that in a Map which can just take care of counting duplicates for you . In your case the name of the item can be the unique identifier (Which would be the key in the Map)
.