How to create a 3 Level Expandable ListView
Recently I had to implement a 3 Level ExpandableListView. So, like most programmers I went searching for an existing solution. After a quick google search there appeared to be quite a few attempts at creating one. I say attempts because none of the ones I found on various blogs or github worked quite right.
After having a look at the source of the ExpandableListView it appears all that's happening behind the scenes is a fancy asynchronous filtering process for the list data. If the ExpandableListView is just a fancy filtering wrapper around a ListView there's no reason we can't make our own to use more levels.
To do this I used a regular ListView and BaseAdapter, a wrapper class, some Interfaces and an AsyncTask to do the filtering.
Here's how it works:
First the NLevelListItem interface. Just a straight forward interface defining some methods we'll use later.
Next is another interface, the NLevelView. This interface is what we'll use to get the View for each level.
The NLevelItem, this implements the above NLevelListItem interface. Since this is just the concrete implementation of the interface the 2 things to note here is the Object wrappedObject and the NLevelView nLevelView. The wrappedObject is what will hold the data that backs the ListView views and the nLevelView will get the View for the BaseAdapter.
And now for the complex part, the NLevelAdapter. Its mostly just a standard BaseAdapter, except for the AsyncFilter class. The AsyncFilter does the filtering in the background, it simply iterates through the list of all NLevelItems and adds the top level items and any items whose ancestors are all expanded.
To do this I used a regular ListView and BaseAdapter, a wrapper class, some Interfaces and an AsyncTask to do the filtering.
Here's how it works:
Let's take a look at the code.
- iterate over a list of all items and determine if it should be shown.
- it should be shown if its the top level item (it's parent is null) or every ancestor is expanded (its parent is expanded and so is its parent's parent and so on).
- if it should be shown we add it to a filteredList and its this filteredList that is used by the ListView to determine what to show.
First the NLevelListItem interface. Just a straight forward interface defining some methods we'll use later.
package com.twocentscode.nexpandable; import android.view.View; public interface NLevelListItem { public boolean isExpanded(); public void toggle(); public NLevelListItem getParent(); public View getView(); }
Next is another interface, the NLevelView. This interface is what we'll use to get the View for each level.
package com.twocentscode.nexpandable; import android.view.View; public interface NLevelView { public View getView(NLevelItem item); }
The NLevelItem, this implements the above NLevelListItem interface. Since this is just the concrete implementation of the interface the 2 things to note here is the Object wrappedObject and the NLevelView nLevelView. The wrappedObject is what will hold the data that backs the ListView views and the nLevelView will get the View for the BaseAdapter.
package com.twocentscode.nexpandable; import android.view.View; public class NLevelItem implements NLevelListItem { private Object wrappedObject; private NLevelItem parent; private NLevelView nLevelView; private boolean isExpanded = false; public NLevelItem(Object wrappedObject, NLevelItem parent, NLevelView nLevelView) { this.wrappedObject = wrappedObject; this.parent = parent; this.nLevelView = nLevelView; } public Object getWrappedObject() { return wrappedObject; } @Override public boolean isExpanded() { return isExpanded; } @Override public NLevelListItem getParent() { return parent; } @Override public View getView() { return nLevelView.getView(this); } @Override public void toggle() { isExpanded = !isExpanded; } }
And now for the complex part, the NLevelAdapter. Its mostly just a standard BaseAdapter, except for the AsyncFilter class. The AsyncFilter does the filtering in the background, it simply iterates through the list of all NLevelItems and adds the top level items and any items whose ancestors are all expanded.
package com.twocentscode.nexpandable; import java.util.ArrayList; import java.util.List; import android.os.AsyncTask; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; public class NLevelAdapter extends BaseAdapter { List<NLevelItem> list; List<NLevelListItem> filtered; public void setFiltered(ArrayList<NLevelListItem> filtered) { this.filtered = filtered; } public NLevelAdapter(List<NLevelItem> list) { this.list = list; this.filtered = filterItems(); } @Override public int getCount() { return filtered.size(); } @Override public NLevelListItem getItem(int arg0) { return filtered.get(arg0); } @Override public long getItemId(int arg0) { return 0; } @Override public View getView(int arg0, View arg1, ViewGroup arg2) { return getItem(arg0).getView(); } public NLevelFilter getFilter() { return new NLevelFilter(); } class NLevelFilter { public void filter() { new AsyncFilter().execute(); } class AsyncFilter extends AsyncTask<Void, Void, ArrayList<NLevelListItem>> { @Override protected ArrayList<NLevelListItem> doInBackground(Void... arg0) { return (ArrayList<NLevelListItem>) filterItems(); } @Override protected void onPostExecute(ArrayList<NLevelListItem> result) { setFiltered(result); NLevelAdapter.this.notifyDataSetChanged(); } } } public List<NLevelListItem> filterItems() { List<NLevelListItem> tempfiltered = new ArrayList<NLevelListItem>(); OUTER: for (NLevelListItem item : list) { //add expanded items and top level items //if parent is null then its a top level item if(item.getParent() == null) { tempfiltered.add(item); } else { //go through each ancestor to make sure they are all expanded NLevelListItem parent = item; while ((parent = parent.getParent())!= null) { if (!parent.isExpanded()){ //one parent was not expanded //skip the rest and continue the OUTER for loop continue OUTER; } } tempfiltered.add(item); } } return tempfiltered; } public void toggle(int arg2) { filtered.get(arg2).toggle(); } }
Now there's only two thinga left: how we build the list for the NLevelAdapter and how we provide the View for the getView() method in the adapter. So let's take a look at the MainActivity.
Here we create the data for the ListView, we create 5 'grandparents' (top level) NLevelItems, then for each grandparent we create a random number (between 1 and 5) of 'parents' (second level) NLevelItems and then for each parent we create a random number (between 1 and 6) of 'children' (third level) NLevelItems.
For each of the NLevelItems we pass in an anonymous instance of NLevelView, this is what supplies the View for the adapter for the each of the NLevelItems (grandparent, parent and children objects). For each of the different Views I'm using the same xml layout and just changing the background color for the different types, green for grandparents, yellow for parents and gray for children.
package com.twocentscode.nexpandable; import java.util.ArrayList; import java.util.List; import java.util.Random; import com.example.expandable3.R; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { List<NLevelItem> list; ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.listView1); list = new ArrayList<NLevelItem>(); Random rng = new Random(); final LayoutInflater inflater = LayoutInflater.from(this); for (int i = 0; i < 5; i++) { final NLevelItem grandParent = new NLevelItem(new SomeObject("GrandParent "+i),null, new NLevelView() { @Override public View getView(NLevelItem item) { View view = inflater.inflate(R.layout.list_item, null); TextView tv = (TextView) view.findViewById(R.id.textView); tv.setBackgroundColor(Color.GREEN); String name = (String) ((SomeObject) item.getWrappedObject()).getName(); tv.setText(name); return view; } }); list.add(grandParent); int numChildren = rng.nextInt(4) + 1; for (int j = 0; j < numChildren; j++) { NLevelItem parent = new NLevelItem(new SomeObject("Parent "+j),grandParent, new NLevelView() { @Override public View getView(NLevelItem item) { View view = inflater.inflate(R.layout.list_item, null); TextView tv = (TextView) view.findViewById(R.id.textView); tv.setBackgroundColor(Color.YELLOW); String name = (String) ((SomeObject) item.getWrappedObject()).getName(); tv.setText(name); return view; } }); list.add(parent); int grandChildren = rng.nextInt(5)+1; for( int k = 0; k < grandChildren; k++) { NLevelItem child = new NLevelItem(new SomeObject("child "+k),parent, new NLevelView() { @Override public View getView(NLevelItem item) { View view = inflater.inflate(R.layout.list_item, null); TextView tv = (TextView) view.findViewById(R.id.textView); tv.setBackgroundColor(Color.GRAY); String name = (String) ((SomeObject) item.getWrappedObject()).getName(); tv.setText(name); return view; } }); list.add(child); } } } NLevelAdapter adapter = new NLevelAdapter(list); listView.setAdapter(adapter); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { ((NLevelAdapter)listView.getAdapter()).toggle(arg2); ((NLevelAdapter)listView.getAdapter()).getFilter().filter(); } }); } class SomeObject { public String name; public SomeObject(String name) { this.name = name; } public String getName() { return name; } } }
And finally the xml files used. activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="NLevelExpandable ListView" /> <ListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/textView1" android:layout_below="@+id/textView1" > </ListView> </RelativeLayout>
And list_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:id="@+id/listItemContainer"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" /> </LinearLayout>
You might have noticed everything is named NLevel... the reason being this code should handle an infinite number of level (in theory). Just nest more items as shown the MainActivity and more levels should be created. If you want you can grab the code from github.
Last but not least some screen shots.
This comment has been removed by the author.
ReplyDeleteYou could change isExpanded=false to isExpanded=true in NLevelItem class which would mean all NLevelItems would be expanded by default.
DeleteThis comment has been removed by the author.
DeleteHi! I would know if there is a method to take item's text of the listview, and if is possible to take also it parent's text.
ReplyDeleteThanks
I hope in an answer
How should xml file look like if I want in the last child item to have image on the left and 2 textview on the right of image?
ReplyDeletewhy my listen item not response if i get grandparent more than 3
ReplyDeletethanks, is there way to expanded one list only the other collapses
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHi,
ReplyDeleteI need to keep check boxes at all the three levels and keep the states of checked and unchecked.
When children are checked, parent must be checked and if all parents are checked, grandparent should be checked. The opposite case implies if grandparent is unchecked, then all parents and children must also be unchecked.
Could you please advise how this can be achieved. Currently, I have created a second level list with its own adapter (sAdapter) as child view in grandparent adapter (pAdapter). The children are being populated as child view from sAdapter. However, I'm facing two issues here:
1. The parents are being populated twice where grandparent.get(groupPosition).getParents().size > 1.
2. When I uncheck any child, parent is being notified ( and changing check box status), but grandparent does not know about this change. I tried passing pAdapter to sAdapter and notify change to it. But that didn't help.
Hi,
Delete1. I don't really understand what you've done here, but you shouldn't need more than 1 adapter for multiple levels.
2. The check boxes, each NLevelItem has a reference to its parent so you can pass the check box change up to the parent. eg item.getParent().someNewMethodToHandleCheckBox() then call notifyDatasetChanged
When I add new grandparents, parents and children once i expand the grandparent list the parent list does not expand under the grandparent list i clicked on but the very last grandparent list how can i fix this
ReplyDeleteI'm sorry I don't quite understand your problem, can you post some of your code?
ReplyDeleteI can't post the code because i keep getting a message telling me my HTML cannot be accepted: Must be at most 4,096 characters
ReplyDeleteI want my code to look like
Advanced Search
Grandparent1
Parent1
GrandParent2
Parent2
Child1
Child2
Child3
Parent3
Child4
Child5
Child6
Parent4
Child7
Child8
Child9
Grandparent3
Parent5
Parent6
Parent7
Parent8
Parent9
Parent10
but when i click on grandparent1 and others what i get is
Grandparent1
Grandparent2
Grandparent3
Parent1
Parent2
Child1
Child2
Child3
Parent3
Child4
Child5
Child6
Parent4
Child7
Child8
Child9
Parent5
Parent6
Parent7
Parent8
Parent9
Parent10
I have the same problem.It is because of adding of data is not correct in your arraylist..
DeleteSorry for the late reply I have been away from my pc. It looks like all the parents have been given the same grandparent as their own parent. So you should take a look at where you're creating your items. Are you using the same code I wrote in the MainActivity or did you write your own, if so can you post the part where you create the children, parents, grandparents, if you can't post the code you could try use pastebin.com and send me the pastebin link
ReplyDeletehow to add childclick listener to this??
ReplyDeleteIt uses a standard ListView so you can use the standard OnItemClickListener
DeletelistView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position,
long id) {
}
});
Thanks for the reply.But the position of the child is not correct with respect to its parent because of its adding procedure.I want exact grand child position.Please help.
DeleteOk, there are 2 lists, the 'filtered' and the 'list', when you say exact grand child position do you mean in the 'list' which holds every item or the 'filtered' which holds only grandparents and any expanded items. The position in the onClickItem is the position in the 'filtered' list. If you need the position in the 'list' then you'd have to get the item first using
DeleteNLevelItem item = adapter.getItem(position);
then get the index of the item in the 'list' using indexOf
int absolutePosition = adapter.getList().indexOf(item);
Is that what you're trying to do?
I want to detect the grand child for putting some intent.But in this case when
DeleteI clicked grand parent also gets the click event.I only want the child click..
I have just ran the code and everything is working as expected, I'm not getting multiple click events in the onItemClickListener
DeleteAll clicks are returning the correct index in the filtered array. Can you post the code in your click listener?
ListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
Delete@Override
public void onItemClick(AdapterView arg0, View arg1, int arg2,
long arg3) {
((NLevelAdapter) listView.getAdapter()).toggle(arg2);
((NLevelAdapter) listView.getAdapter()).getFilter().filter();
NLevelListItem item = adapter.getItem(arg2);
//int absolutePosition = adapter.getList().indexOf(item);
NLevelItem item = adapter.getItem(position);
//int absolutePosition = adapter.getList().indexOf(item);
}
});
int absolutePosition = adapter.getList().indexOf(item); is not working.".getList()" method not working..
There is no getList() in the adapter, you'll have to add it yourself.
DeleteAdd to the NLevelAdapter
public List getList() {
return this.list;
}
Ok..thanks.But I have child id array and child name array.By using child name array I created grand child using this array.
Deleteexample.
Grand parent:Fabrics (it is created by grandparent array,It is have ids array too. example for fabrics id=3234)
its child: Matching Cloth materials (it is created by child array,It is have ids array too. example..)
grand child: Cotton Lining cloth (it is created by grandchild array,It is have ids array too. example id=65467)
I want that id 65467,When clicking on its grand child. Also Each grand child has its own id.
In the current case "absolutePosition" getting the position in an increment manner.that is for grand parent it is "1".and its child it is "2".
Is there a way to get its id of child when clicking it?.
Anyway Thanks for Your efforts and reply..:)
Basically getting the correct position is the way to get correct id from the array
DeleteSorry I'm not following your example and I think i would need to see your code to help you.
DeleteIf your comfortable with showing me your code you can post your code to pastebin (be sure to create an account and log in if you want to be able to delete the paste after) and send me the link or if your code is on github you can send me the link and i'll have a look
I am absolutely greatful to show you my code
Deletehere is my link:http://pastebin.com/raw/d21XdabE
The link is set to private so I can't view, you'll need to make it public
DeleteThis comment has been removed by the author.
DeleteI made it as public..
Deletehttp://pastebin.com/raw/d21XdabE
ok, I'll take a look, I'm in work at the moment so it'll be a while before I'm able to go through your code but I'll respond as soon as I can.
DeleteOk thanks..
DeleteAlright here's what I've done, in the click listener
Delete@Override
public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
((NLevelAdapter) listView.getAdapter()).toggle(arg2);
((NLevelAdapter) listView.getAdapter()).getFilter().filter();
//because NLevelItem implements NLevelListItem we can cast the NLevelListItem back to NLevelItem
NLevelItem item = (NLevelItem)adapter.getItem(arg2);
//now we have the NLevelItem, we can get the wrapped object
//we need to cast that to the type we passed in the constructor
//in this case the SomeObject class
//now we can get the id of our object
//eg Clicking Cotton Lining Cloth will give the id 300018
//{ "third_category_id":"300018","third_category_name":"Cotton Lining cloth", "second_category_id":"200005" },
//which looks correct to me
String id = ((SomeObject)item.getWrappedObject()).getId();
Log.i("DEBUG", "item="+item.getWrappedObject().toString());
Log.i("DEBUG", "id of clicked="+id);
}
});
So one thing to note is that you're not passing in the ids for the parent/grandparent in the constructor for the parent/grandparent SomeObjects so the id will be null for those, you will need to pass in the id if you want to get their ids.
If you need to get the parent of a clicked object then you can use this line
NLevelItem parent = (NLevelItem) item.getParent();
Also I added a toString() method to the SomeObject class
public String toString() {
return "id="+id+"name="+name;
}
I am new to android.And you helped me a lot.Thank you very much.It is working perfectly..:).
DeleteHow to put click listener to child only
DeleteAdd a level to constructor. then check for level
Deleteclass ListObject
{
public String name;
public int level;
}
NLevelItem grandParent = new NLevelItem(new ListObject(model.get(i).LocName, 0, i, -1, -1), null, new NLevelView()
this i comes from for loop and defines its level.
inside
listView.setOnItemClickListener(new OnItemClickListener()
{
@Override
public void onItemClick(final AdapterView parent, final View view, final int position, long id)
{
NLevelItem item = (NLevelItem) adapter.getItem(position);
final ListObject listObject = (ListObject) item.getWrappedObject();
if (listObject.getLevel() == 2)
{
change level as you need.
new ListObject(model.get(i).LocName, 0, i,
Deletesorry 0 after LocName is the level not i.
This comment has been removed by the author.
ReplyDeleteI want a indicator to show that whether it expand or not.I added a image view to list item.But I can't change the image when expanded.How can I do this?
ReplyDeleteYou would change the image loaded in the imageview in the getView of the expanded item.
Delete@Override
public View getView(NLevelItem item) {
View view = inflater.inflate(R.layout.list_item, null);
TextView tv = (TextView) view.findViewById(R.id.textView);
tv.setBackgroundColor(Color.YELLOW);
if (item.isExpanded) {
tv.setBackgroundColor(Color.BLACK);//or in your case instead of background colors, change the image in the imageView
}
String name = (String) ((SomeObject) item.getWrappedObject()).getName();
tv.setText(name);
return view;
}
});
Its working fine thanks..:)
Deletein setOnItemClickListener
Deleteif (item.isExpanded())
{
view.findViewById(R.id.select_icon).setBackgroundResource(R.drawable.list_item_selector_icon_down);
}
else
{
view.findViewById(R.id.select_icon).setBackgroundResource(R.drawable.list_item_selector_icon_up);
}
does the trick.
If I need two touch points.That is Can I put a click listener on text view other than onItemclicklistener?.That is the List view has a click listener and the text in it has also the click listener seperatly?
ReplyDeleteYes you can click listeners to views inside a row, however there can be unexpected side effects with certain Views but Views such as a button should be fine though
ReplyDeleteIs that possible after OnItemclick listener?,If yes how?
ReplyDeletejust add a Button to the View layout and set a click listener using setOnCLickListener
ReplyDeleteI need clicked item name in each level how to do this??
ReplyDeleteIn the OnItemClickListener
DeleteNLevelItem item = (NLevelItem)adapter.getItem(arg2);
String name = ((SomeObject)item.getWrappedObject()).getName();
if one listview open other listview collapsed, how can we achieve this and if grandparent litview collapsed parent listview automatically collapsed how we can do this? please replay me as soon as possible.
ReplyDeletehow collapse listview parent and grandparent manually
ReplyDeletehi
ReplyDeletehow to add + label to specific parent item that have a child group like this
parent(no childs)
+ parent (have childs)
+(child) (have childs)
+ parent (have childs)
(child) (not childs)
(child) (not childs)
+(child) (have childs)
(child) (have childs)
hello,
ReplyDeleteCould you plz let me know how can i provide the different names for grandparent,parent and child ?
Thanks
Hello ,
ReplyDeleteHow to implement search Functionality in the expandable list with four level. Searchable item should be shown as they are in the level.
for example is we search for text "abc" which is at third level then search view should shown like following -
grandparent
---- parent
-----child
----- abc
Thanks.
Please,
DeleteCould anyone suggest me how to do search functionality in NLevelItem expandable listview? your answer would be appreciable.
Thanks.
Depends on what you want to display?
DeleteIf you search for abc, do you want to also see the parent and grandparent of abc?
Do you only want to search for the child or do you want results where abc matches in the parent or grandparents name?
Regardless of what you need, you can do this with a class similar to the NLevelFilter class and a new filterItems method where the filter is based on whether the name matches your search terms, then add the appropriate items to the filtered List.
yes, if i search for abc, then i want to show parent and grandparent with it. basically i want a single filter method which works for all level search. and if an item found, then all of its parent should be visible in the search result. Is it possible to create a single filter method for all level search? If possible, could you please suggest/give me that method?
DeleteThanks.
This is just a rough draft, you'll have to do some work to it to get it to work. Create a new Filter class similar to the NLevelFilter and a new AsyncTask to do the search filter.
Deleteclass NLevelSearchFilter {
public void filter(String searchTerms) {
new AsyncSearchFilter(searchTerms).execute();
}
class AsyncSearchFilter extends AsyncTask> {
String searchTerms;
public AsyncSearchFilter(String searchTerms) {
this.searchTerms = searchTerms;
}
@Override
protected ArrayList doInBackground(Void... arg0) {
return (ArrayList) searchFilter(searchTerms);
}
@Override
protected void onPostExecute(ArrayList result) {
setFiltered(result);
NLevelAdapter.this.notifyDataSetChanged();
}
}
}
public List searchFilter(String searchTerms) {
for (NLevelListItem item : list) {
NLevelItem temp = (NLevelItem)item;
if (((SomeObject)temp.getWrappedObject()).getName().contains(searchTerms)) {
//item matches the search term
//expand all parents
NLevelListItem parent = item;
while ((parent = parent.getParent())!= null) {
if (!parent.isExpanded()){
parent.toggle();
}
}
}
}
//now that any item that matched our search terms has been expanded
//we can now use the normal filter to populate the data
return filterItems();
}
Then you can perform the filtering by calling
((NLevelAdapter)listView.getAdapter()).getSearchFilter().filter("abc");
how do i set and change imageview in the grandparent such as expand icon and collapse icon?
ReplyDeletei tried but its reflecting only in the last grandparent(i used grandparent.isExpanded() to check and set) but grandparent reflects to only the last added grandparent. i need to set it for all grandparents.
Reply fast!
i need grandparent \/(imageview) when not expanded and then grandparent/\(imageview) when expanded.
and if possible for parent and child also!
I can not click the item, so how can I click on the item in the list.
ReplyDeleteMy list is as follows.
header
- item1
-- chile1
-- chile2
-item2
-- chile1
---d1
---d2
header2
header3
-item1
and clicked code:
final NLevelAdapter adapter = new NLevelAdapter(list);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView arg0, View arg1, int arg2,
long arg3) {
((NLevelAdapter) listView.getAdapter()).toggle(arg2);
((NLevelAdapter) listView.getAdapter()).getFilter().filter();
NLevelItem item = (NLevelItem)adapter.getItem(arg2);
String row = ((SomeObject)item.getWrappedObject()).getName();
/* if (?) {
Intent intent = new Intent(Marjaa_Categories_Activity.this, Marjaa_single_Activity.class);
intent.putExtra("catID", catID);
intent.putExtra("cat_id", row);
startActivity(intent);
}*/
}
});
Hi Chris,
ReplyDeleteVery good code. Thank you and well done.
I have a problem with scrolling.
when I click on row I add some dynamic content (textviews) to a row inside the xml like
View view = inflater.inflate(R.layout.fourth_row, null);
LinearLayout row_information = (LinearLayout) view.findViewById(R.id.row_information);
TextView tv = new TextView(MainActivity.this);
tv.setText(getResources().getString(R.string.days) + ": " + lDays);
tv.setTextColor(getResources().getColor(R.color.white));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(10, 10, 10, 10);
row_information.addView(tv);
this is working normally. When I scroll up or down this textview disappears. I need to implement ViewHolder pattern here to remember their contents.
but at this point
new NLevelView()
{
@Override
public View getView(NLevelItem item)
{
if(item.getView() == null)
{
Log.e("ALP", "view is null");
} else
{
Log.e("ALP", "view is NOT null");
}
this stucks...
normal BaseAdapter code:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_entry, null);
holder = new ViewHolder();
holder.nameTextView = (TextView) convertView.findViewById(R.id.person_name);
holder.surnameTextView = (TextView) convertView.findViewById(R.id.person_surname);
holder.personImageView = (ImageView) convertView.findViewById(R.id.person_image);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
Person person = getItem(position);
holder.nameTextView.setText(person.getName());
holder.surnameTextView.setText(person.getSurname());
//holder.personImageView.setImageBitmap(person.getImage());
return convertView;
}
there is no convertview or view at the item.getView() code.
how can we do this?
Hi ,
ReplyDeletethank you so much for the explanation ,i was able to understand this nLevel expandable list view.Iam very new to android.
I was working on this and iam facing an issue,it would be a great help if you could help me resolve.
The problem is:
I have a textview associated with every list item,only a few lines are shown at first.
On click of the text description,it will show me the full text.
the issue is:
i have my parent and first level of children visible at the first look.
Now if i click the text description it will show the full text.
on clicking the listview,it is supposed to hide the children listview alone,but it is taking back my textview also to inital state,that is only few lines are shown.i want it to retain the state of textview
how to api calling this app
ReplyDeleteThanks, this is great. It works like a charm.
ReplyDeleteHi, So I successfully created a 4 Level list using your code. I have used custom layouts for the each level with each level having add and delete buttons where the delete button deletes the item and its subitems and the add button adds children to the parent item. I am using the following modification to the getView() method in the NLevelAdapter.java class https://pastebin.com/CBFR9L6H but unfortunately the onClickListener is being only triggered for the first two levels of the list and the other two levels are being ignored.
ReplyDeleteExpanding the listview is awesome and tq for coding...but when i expand one the other should be collapse can u help me
ReplyDeleteMany days of work, saved my life. Thanks
ReplyDeletehow to expand all the grandparent and parent items and set the height of the listview dynamically from actitvity ? Pls help me.
ReplyDeleteused toggle() method on both of them, done.. Really great code....
Delete