I'm writing an ExpandableListActivity with a SimpleCursorTreeAdapter that queries a DB. I added a button inside very child, and now i'm having bad time getting info on the item from the list that its button is clicked. I think that my problem is that i don't well understand how to handle data within the adapter. Most of the examples are about listadapter like this one.
My adapter got getChildView implementation and what i cannot achieve is to retrieve the _id of the clicked group from the original cursor. Because i didn't know how, i tried in the following code to get the name from the group textview but in every child that i click i get the name of the first item in the list.
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View v = super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);
v.inflate(getApplicationContext(),R.layout.productsexpchilditem, null);
Button button = (Button)v.findViewById(R.id.button1);
String name=((TextView)parent.findViewById(R.id.txt_exp_products_name_item)).getText().toString();
button.setTag(name);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(ProductsActivityExp.this, "TOAST "+v.getTag(), Toast.LENGTH_SHORT).show();
}
});
return v;
}
BTY I didn't implemented the getGroupView method, cause when I did it I lost all the displayed text in the groups (but not in the child). I really think the work with cursorTreeAdapter got specific implementation different then listadapter.
I didn't used ExpandableListView, but it seems strange that you get name value via parent. Its not surprising that you get same name for all buttons.
Can you explain in details, what you want to do?
Related
It got me wondering on how to implement an "onChildChildClickListener" into this three level expandable list view after answering the question of how to populate three level expandable list view (Populate different arrays in third layer of expandableListView).
How does one implement the third level being Clickable?
Example code by BKN is published on githube here:
https://github.com/ngocchung/ThreeLevelExpListView
Does anybody have an idea?
Help would be gladly appreciated as I would like to implement this into an showcase app as a part of my Masterthesis.
Found the solution after reading the comments in this How to add Three Level ListView in ExpandableListView in android
this needs to be implemented in the ParentLevelAdapter in the public View getChildView part.
#Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final CustomExpListView secondLevelExpListView = new CustomExpListView(this.mContext);
String parentNode = (String) getGroup(groupPosition);
secondLevelExpListView.setAdapter(new SecondLevelAdapter(this.mContext, mListData_SecondLevel_Map.get(parentNode), mListData_ThirdLevel_Map));
secondLevelExpListView.setGroupIndicator(null);
//newcode
secondLevelExpListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener(){
#Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition,long id)
{ String selectText = ((TextView) v).getText().toString();
switch (selectText){
case "ItemName you want to do something with":
//Actions you want to do when clicking this item
break;
case "ItemName2 you want to do something with":
//Actions you want to do when clicking this second item
break;
default:
//default actions on all other items
}
return false;}
});
return secondLevelExpListView;
}
I have an expandlistview in which I have included a button on the the group. When I click on the button, it is supposed to save the data associated with the button and also it has to redraw the button, based on the value of the button. The issue I am having is that it is not only redrawing itself but also it is redrawing some other buttons. It is quite difficult to understand and explain what is happening as it seems to redraw any button it at random. Please note that the save part is working correctly.
Can anyone tell me, what could be wrong with the piece of code below. The only thing I want to achieve is redraw the button that is being clicked only and not any other button in the expandlistview.
groupHolder.Favourite.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
String itemKey = Holder.Favourite.getTag().toString();
Boolean starred = Client.data.get(itemKey.toLowerCase());
Client.writeStarred(view.getContext(), itemKey.toLowerCase(), starred);
if (starred)
((ImageButton) view).setImageDrawable(view.getContext().getResources().getDrawable(R.drawable.ic_cat_star_yellow));
else
((ImageButton) view).setImageDrawable(view.getContext().getResources().getDrawable(R.drawable.ic_cat_star));
}
});
Part of the getGroupView
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupViewHolder Holder;
final GroupEvent group = (GroupEvent) getGroup(groupPosition);
if (group.Starred)
Holder.Favourite.setImageDrawable(convertView.getContext().getResources().getDrawable(R.drawable.ic_cat_star_yellow));
});
I have changed the code to the following to add notifyDataSetChanged(); , but this too does not seem to work.
groupHolder.ButtonFavourite.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
String itemKey = gpHolder.ButtonFavourite.getTag().toString();
Boolean starred = Client.data.get(itemKey.toLowerCase());
Client.writeStarred(view.getContext(), itemKey.toLowerCase(), starred);
notifyDataSetChanged();
}
});
The view is redrawing buttons at random due to view recycling.
For adapter views, the event handlers should be used to update model state and getView() [or for ExpandableListView, getGroupView() and getChildView()] should render the views based on that state.
In getGroupView(), check the starred flag for the item and set your image drawable accordingly.
Make sure you treat your view as "dirty" since it may be recycled and explicitly set the image drawable value every time:
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
GroupViewHolder Holder;
final GroupEvent group = (GroupEvent) getGroup(groupPosition);
...
Holder.Favourite.setImageDrawable(convertView.getContext().getResources().getDrawable(
group.Starred ? R.drawable.ic_cat_star_yellow : R.drawable.ic_cat_star));
}
Basically I have 2 Views that both use an Adapter to populate.
An ExpandableListView. ExpandableListView gridHostList;
A custom View that works very similarly to GridView (it's called StaggeredGridView) StaggeredGridView grid;
Their Adapters in order:
HostListAdapter which inherits from BaseExpandableListAdapter.
GridAdapter which inherits from BaseAdapter.
The reason for this is I need an expandable list with varying numbers of parents or groups where each group contains a grid that also has a varying number of children. I looked into many ways of achieving this and I think this is the best but I am open to alternatives.
In the getChildView() method of HostListAdapter I make my grid and this works fine.
#Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
convertView = mInflater.inflate(R.layout.layout_containing_grid, null);
StaggeredGridView gridView = (StaggeredGridView) convertView.findViewById(R.id.grid_view);
}
Now when I set the adapter of my StaggeredGridView here as shown below everything works as expected.
#Override
public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
convertView = mInflater.inflate(R.layout.layout_containing_grid, null);
StaggeredGridView gridView = (StaggeredGridView) convertView.findViewById(R.id.grid_view);
gridView.setAdapter(mGridAdapter);
}
That works fine. However I want to set the adapter from the Fragment which contains all of this (it's in a ViewPager). To do this I store the view returned by the hostListAdapter in a Hashmap with the Hashmap key being a Class I made that contains an ArrayList.
gridHostList = (GridHostList) V.findViewById(R.id.gridHostList);
if (!gridsHashMap.containsKey(dataForThisGrid)) {
gridsHashMap.put(dataForThisGrid, getGrid(0, gridsHashMap.get(dataForThisGrid)));
StaggeredGridView gridView = (StaggeredGridView) gridsHashMap.get(dataForThisGrid).findViewById(R.id.grid_view);
if (gridView.getAdapter() == null) {
gridView.setAdapter(new GridAdapter(context);
}
private View getGrid(int groupPosition, View convertView) {
View v;
v = gridHostList.getExpandableListAdapter().getChildView(groupPosition, 0, true, convertView, gridHostList);
return v;
}
}
I've tried this without any of the fancy HashMap stuff or logic of any kind to check if that was the problem and found nothing. I know I am actually getting a View from the parent adapter. gridAdapter.getCount() is being called by the system and returning a positive int as it should. However the problem seems to come because for some reason gridAdapter.getView is never called.
So what I am trying to figure out is why gridAdapter.getView is called when I set it in the hostListAdapter, but not when I set it in the Fragment which contains this all.
Please forgive minor errors in the code here, I made many changes in the StackOverflow editor (mostly removing logs and changing names for clarity). Thanks for your time.
In your getGrid method you are getting the StaggeredGridView and you are adding it to the gridsHashMap with the key dataForThisGrid . But when you are retrieving it from the gridsHashMap you are doing it as (StaggeredGridView) gridsHashMap.get(dataForThisGrid).findViewById(R.id.grid_view);.
I think you have to retrieve it using just
(StaggeredGridView) gridsHashMap.get(dataForThisGrid);
Note: I have seen people advising not to call the getView or getChildView method directly as calling them will result in inflating the respective view.
I have subclassed BaseExpandableListAdapter in the rows for the BaseExpandableListView I'm having a CheckedTextView. What I want to achieve is that there can only be checked items in one of the groups in the BaseExpandableListView.
So if there is already checked items in group 0 and the user tries to check any items in group 1 then a toast message should display saying something that he has to uncheck the items in group 0 or something like that.
So far my code looks like this:
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView,
ViewGroup parent) {
...
holder.checkedTextView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
((CheckedTextView) v).toggle();
}
});
holder.checkedTextView.setText(person.getName());
holder.checkedTextView.setChecked(person.isTracked());
return convertView;
}
I suppose I need to get a reference or something to BaseExpandableListView inside the onClick method to find out which group the currently toggled CheckedTextView is inside?
I'm not sure if my terminology is correct since I just started coding on Android.
I figured out how to do it with the int groupPosition, int childPosition variables.
I am new to android and am trying to develop a new android app. But I am struggling to siolve one of the problems in my project.
I am using a listview extended from baseadapter and need to add a button in each row of thelistview. When I click on the button in any row of the listview, I want that it should be removed. However when I do so, some of the other buttons also get removed in the listview.
How can I solve this problem? Thank you..
You have an adapter, activity and some sort of data source
In your adapter you attach some data to buttons to be able to tell one from another:
public class ExpAdapter extends ListAdapter {
#Override
public View getView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
/* SOME CODE HERE*/
convertViewButton.setTag(buttonId);
return convertView;
}
/* SOME CODE HERE*/
}
in your activity you mark button id as the one to be hidden:
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
storageOfHiddenButtonsIds.add((Long)arg1.getTag());
}};
and then ListAdapter changes like this:
#Override
public View getView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
/* SOME CODE HERE*/
convertViewButton.setTag(buttonId);
if(storageOfHiddenButtonsIds.contains(buttonId))
{
convertViewButton.setVisiblity(View.GONE);
}
return convertView;
}
and when you want your adatper to change you, don't forget to call
this.expAdapterAllTaks.notifyDataSetChanged();
Sorry for any errors in my code, but i just wanted to give you an idea.
I faced same type of problem. ListView's setOnItemClickListener not works if you add item like a button on every listView item. Solution is use onClick in the list Item layout(which you use in custom adapter file) as
<ImageButton
android:id="#+id/my_delete"
android:onClick="onDeleteButtonClickListener"
... and so on />
where onDeleteButtonClickListener is a method in the activity where you set the adapter in listview.
public void onDeleteButtonClickListener(View v) {
// your code
}
here listItem means the individual row item of a ListView
Helpful Link: Button in ListView item