the problem goes is that everytime I add more than one Child to a GroupItem in my ExpandableListView, the item duplicates itself with the previous child. I have narrowed it down to the getChild() method in my ExpandableListView (custom) adapter.
The getChild() method looks like this:
public Object getChild(int groupPosition, int childPosition) {
return rCollection.get(weekData.get(groupPosition)).get(childPosition);
}
Where rCollection = Map<String, List<Custom>>;
and weekData = List<String>;
How do I change the getChild to return only one item per request so I dont get duplicates? I cannot use a for-loop because if I change the groupPosition and childPosition to Arrays I will have to implement the method again.
To Illustrate, this is what the issue looks like:
How do I exclude the Item 2 from being picked up by the first time it is called, and how do I exclude item 1 from being called the second time it is called? And so on.
Thank you for reading and all the help.
#Override
public int getChildCount(.....)
{
return 2;
}
If you are sure that for every item there are only 2 subitems
Sorry my bad this is the right method you want.
EDIT
#Override
public int getChildrenCount(int groupPosition)
{
return (rCollection.get(weekdata.get(groupPosition())).size();
}
This will return the size (length) of your List<Custom> for a map.
balance paranthesis if needed
am not sure if you found a solution but here is what worked for me; since i was returning a recyclerview in the child view, just return 1 in getChildrenCount() method.
That's it
I dug it out of some old repo, I think this is what I ended up doing.
public int getChildrenCount(int groupPosition) {
// Fixes a bunch of NPE when the groupPosition = NULL. This way it checks and returns 0 when it = null.
List<MySQLWeek> group = rCollection.get(weekData.get(groupPosition));
if (group == null){
return 0;
}
return group.size();
}
Related
i am trying to add section/header in recycle View
as we have to handle section stuff in
#Override
public int getItemViewType(int position) {
// here your custom logic to choose the view type
return position == 0 ? section: item;
}
but i am having arraylist which have n number of data . so say 1st section may have 10 row where as 2nd may have 2 row .so how to define section in this case .where i come to know this is the end of 1st section ? and put 2nd one
Iterate over each model and remember the previous section name of each model item. When ever you find a new section name, just map the index.
In your adapter return items count that is fewer than data set.
#Override
public int getItemCount(){
return mData.size() + mSections.size();
}
Always use position + 1, because you are always one position ahead.
Whenever you reach for position that belongs to the mapped indexes, return section type and bind it accordingly:
#Override
public int getItemViewType(int position) {
// here your custom logic to choose the view type
return isPositionSectionIndex(position) ? VIEW_TYPE_SECTION: VIEW_TYPE_ITEM;
}
I have a list of products, each row has a function "Save" which will store the item product to local database. I'm using SwipeMenuListView via https://github.com/baoyongzhang/SwipeMenuListView and i have to check record is existed or not in getItemViewType in ListAdapter to remove function Save of the row which saved.
But the problem is, the "check record is existed or not" made my listview freeze after notifyDataSetChanged for a while (click "Save" then notifyDataSetChanged then list is freezed until i touch listview again).
How should i fix it?
Every suggestion will be highly appreciated. Thanks in advance. Here is my code:
#Override
public boolean onMenuItemClick(int position, SwipeMenu menu, int index) {
switch (index) {
case 0:
break;
case 1:
ProductDetailsVo.ProductInfo productInfo = listResult.get(position);
insertProductToDB(productInfo);
break;
}
and method insertProductToDB:
private void insertProductToDB(ProductDetailsVo.ProductInfo productInfo) {
databaseManager.insertProductToDB(productInfo);
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
Adapter:
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
if (databaseManager.isProductSaved(listProds.get(position).getProductId())) {// cause listview freeze
return 1;
}
return 0;
}
So the freezes are probably due the numerous calls to isProductSaved, you can be sure of that by commenting them and test, or by profiling your app with the Android Device Monitor.
You can easily remove that database access by adding a field exists to your products. The default value would be false and insertProductToDB would set it to true if the insertion succeeds. With that your getViewType will be much faster.
#Override
public int getItemViewType(int position) {
if (listProds.get(position).isExists())) {
return 1;
}
return 0;
}
If you don't want to alter your model object with an extra field, you can also maintain a map like a SparseArray in the adapter. It would contain the id of the saved products.
Taking for example Gmail App, on my Navigation Drawer, I want a ListView that is grouped by section, similar to inbox, all labels.
Is this behavior achieved by using multiple ListView separated by a "header" TextView (which I have to build manually obviously), or is this section-grouped behavior supported by the Adapter or ListView?
Don't use multiple ListViews, it will mess things up for the scroll.
What you describe can be achieve by using only one ListView + adapter with multiple item view types like this:
public class MyAdapter extends ArrayAdapter<Object> {
// It's very important that the first item have a value of 0.
// If not, the adapter won't work properly (I didn't figure out why yet)
private int TYPE_SEPARATOR = 0;
private int TYPE_DATA = 1;
class Separator {
String title;
}
public MyAdapter(Context context, int resource) {
super(context, resource);
}
#Override
public boolean areAllItemsEnabled() {
return false;
}
#Override
public int getItemViewType(int position) {
if (getItem(position).getClass().isAssignableFrom(Separator.class)) {
return TYPE_SEPARATOR;
}
return TYPE_DATA;
}
#Override
public int getViewTypeCount() {
// Assuming you have only 2 view types
return 2;
}
#Override
public boolean isEnabled(int position) {
// Mark separators as not enabled. That way, the onclick and onlongclik listener
// won't be triggered for those items.
return getItemViewType(position) != TYPE_SEPARATOR;
}
}
You just have to implement your own getView method for a correct rendering.
I am not sure exactly how the Gmail app achieves this behavior, but it seems as though you should work on a custom adapter. Using multiple list views would not be a productive way to approach this problem, as one wants to keep the rows of data (messages) together in single list items.
I'm trying to implement my own StickyGridHeadersBaseAdapter, my current source code here - http://paste.org.ru/?11jrjh, and I use it like
ModeAdapter adapter = new ModeAdapter(this);
modeGridView.setAdapter(adapter);
Problems which I have is that
1) I have no idea how to call notifyDataSetChanged() for this adapter, so I can't change items
2) And implementation of AdapterView.OnItemClickListener (http://paste.org.ru/?mvgt7b) works strange
Mode mode = (Mode) adapter.getItem(position);
returns null for items with 1st and 2nd positions, item on 3rd position is actual 1st item in adapter.
Where is my fault here?
One more question is why I can't cast adapterView.getAdapter() in my OnItemClickListener to my ModeAdapter class. What if I want to call notifyDataSetChanged() here?
I didn't find any examples for custom implementation of StickyGridHeadersBaseAdapter here.
Thanks in advance.
I had the same issue as you 2):
after the first header i got the item of the previous row, after the second header got the item of two rows up, etc...
The reason is the following:
StickyHeadersGridView:
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mOnItemClickListener.onItemClick(parent, view, mAdapter.translatePosition(position).mPosition, id);
}
The position is corrected. so in your onItemClick you get the corrected value of position.
If than you request the item with: Mode mode = (Mode) adapter.getItem(position);
you get StickyGridHeadersBaseAdapterWrapper.getItem(int pos)
#Override
public Object getItem(int position) throws ArrayIndexOutOfBoundsException {
Position adapterPosition = translatePosition(position);
if (adapterPosition.mPosition == POSITION_FILLER || adapterPosition.mPosition == POSITION_HEADER) {
// Fake entry in view.
return null;
}
return mDelegate.getItem(adapterPosition.mPosition);
}
In StickyGridHeadersBaseAdapterWrapper.getItem() position gets corrected for the second time which causes the wrong item to be returned...
I added a work-around:
In StickyHeadersBaseAdapterWrapper I added:
public Object getItemAtDelegatePosition(int pos) {
return mDelegate.getItem(pos);
}
And I use this in onItemClick:
Mode item = (Mode) ((StickyGridHeadersBaseAdapterWrapper)parent.getAdapter()).getItemAtDelegatePosition(position);
An easier way to get an item would be:
StickyGridHeadersBaseAdapterWrapper wrapper = (StickyGridHeadersBaseAdapterWrapper) parent.getAdapter();
Mode item = (Mode ) wrapper.getWrappedAdapter().getItem(position);
I have a BaseExpandableListAdapter class and getChildView() has to return only a couple rows. But, of course, returning null will crash the app and setting the visibility to GONE will create a blank space in the list.
So, the user has a checkbox in each row, and when one is checked the next time he opens the list it won't appear (like being deleted from the ArrayAdapter, but I can't do that).
Any good option?
EDIT
#Override
public int getChildrenCount(int groupPosition) {
int childrenCount = categories.get(groupPosition).size();
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
/** If the user wants to remove the completed items */
if (settings.getBoolean("deleteCompletedItemsPref", false) == true) {
for (int childPosition=0; childPosition<childrenCount; childPosition++) {
if (categories.get(groupPosition).getItem(childPosition).isChecked()) {
parent.removeViewAt(childPosition);
}
}
}
return childrenCount;
}
Here I run the group's children and try to remove the unwanted views, although I can't remove views here because is an AdapterView.
your BaseExpandableListAdapter must have implemented a getChildrenCount() method. you can make it return the size of your category list (or maybe a copy of the list).
public int getChildrenCount(int groupPosition) {
return categories.get(groupPosition).size();
}
Then simply remove the child position if it's checked (preferably in a click listener). Of course you'd also need to adjust your data set accordingly. perhaps make it an arraylist if it isn't then remove the same position in it.