In this tutorial we learn to create an ExpandableListView simulating a Department Store where products belong to a certain department. We initially load our list with some data, then dynamically add items to the list by checking for new department and add a group otherwise just add the item to the existing department. We also associate listeners to alert which Department or Product was clicked on. We also learn how to programmatically expand and collapse all groups or just one at a time.
If you have worked with ListView then it's not that complicated either. All you have to do is extend the BaseExpandableListAdapter and then attach that to the ExpandableListView. In the BaseExpandableListAdapter we have to custom code 2 methods getChildView() and getGroupView() to display our group information and the child row information. You can create custom layouts for each one and then inflate them using LayoutInflater. Here is how ...
Source for Android Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.as400samplecode" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Source for strings.xml
<resources> <string name="app_name">Expandable List View</string> <string name="add">Add</string> <string name="menu_settings">Settings</string> <string name="title_activity_main">MainActivity</string> <string name="product_hint">Enter Products for the Store</string> <string name="department_store">My Department Store …</string> <string-array name="dept_array"> <item>Apparel</item> <item>Beauty</item> <item>Electronics</item> <item>Grocery</item> <item>Home Improvement</item> <item>Jewelry</item> <item>Pharmacy</item> </string-array> <color name="snow">#eee9e9</color> </resources>
Source for styles.xml
<resources> <style name="AppTheme" parent="android:Theme.Holo.Light" /> </resources>
Main activity layout activity_main.xml
<?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Spinner android:id="@+id/department" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:textStyle="bold" /> <Button android:id="@+id/add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_below="@id/department" android:text="@string/add" /> <EditText android:id="@+id/product" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignBaseline="@id/add" android:layout_alignParentLeft="true" android:layout_below="@id/department" android:layout_toLeftOf="@id/add" android:ems="10" android:hint="@string/product_hint" android:inputType="text" /> <TextView android:id="@+id/textView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@id/product" android:layout_margin="5dp" android:background="@color/snow" android:padding="5dp" android:text="@string/department_store" android:textAppearance="?android:attr/textAppearanceMedium" android:textStyle="bold" /> <ExpandableListView android:id="@+id/myList" android:layout_width="match_parent" android:layout_height="fill_parent" android:layout_below="@id/textView1" /> </RelativeLayout>
Group header layout group_heading.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="55dip" android:orientation="vertical" > <TextView android:id="@+id/heading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="35sp" android:textAppearance="?android:attr/textAppearanceLarge" android:textStyle="bold" /> </LinearLayout>
Child row layout child_row.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/sequence" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:paddingLeft="35sp" android:textAppearance="?android:attr/textAppearanceMedium" /> <TextView android:id="@+id/childItem" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toRightOf="@id/sequence" android:textAppearance="?android:attr/textAppearanceMedium" /> </RelativeLayout>
Source for Child object DetailInfo.java
package com.as400samplecode; public class DetailInfo { private String sequence = ""; private String name = ""; public String getSequence() { return sequence; } public void setSequence(String sequence) { this.sequence = sequence; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Source for Group object HeaderInfo.java
package com.as400samplecode; import java.util.ArrayList; public class HeaderInfo { private String name; private ArrayList<DetailInfo> productList = new ArrayList<DetailInfo>();; public String getName() { return name; } public void setName(String name) { this.name = name; } public ArrayList<DetailInfo> getProductList() { return productList; } public void setProductList(ArrayList<DetailInfo> productList) { this.productList = productList; } }
Source for BaseExpandableListAdapter MyListAdapter.java
package com.as400samplecode; import java.util.ArrayList; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.TextView; public class MyListAdapter extends BaseExpandableListAdapter { private Context context; private ArrayList<HeaderInfo> deptList; public MyListAdapter(Context context, ArrayList<HeaderInfo> deptList) { this.context = context; this.deptList = deptList; } @Override public Object getChild(int groupPosition, int childPosition) { ArrayList<DetailInfo> productList = deptList.get(groupPosition).getProductList(); return productList.get(childPosition); } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, ViewGroup parent) { DetailInfo detailInfo = (DetailInfo) getChild(groupPosition, childPosition); if (view == null) { LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = infalInflater.inflate(R.layout.child_row, null); } TextView sequence = (TextView) view.findViewById(R.id.sequence); sequence.setText(detailInfo.getSequence().trim() + ") "); TextView childItem = (TextView) view.findViewById(R.id.childItem); childItem.setText(detailInfo.getName().trim()); return view; } @Override public int getChildrenCount(int groupPosition) { ArrayList<DetailInfo> productList = deptList.get(groupPosition).getProductList(); return productList.size(); } @Override public Object getGroup(int groupPosition) { return deptList.get(groupPosition); } @Override public int getGroupCount() { return deptList.size(); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public View getGroupView(int groupPosition, boolean isLastChild, View view, ViewGroup parent) { HeaderInfo headerInfo = (HeaderInfo) getGroup(groupPosition); if (view == null) { LayoutInflater inf = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inf.inflate(R.layout.group_heading, null); } TextView heading = (TextView) view.findViewById(R.id.heading); heading.setText(headerInfo.getName().trim()); return view; } @Override public boolean hasStableIds() { return true; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } }
Source for the main Android activity MainActivity.java
package com.as400samplecode; import java.util.ArrayList; import java.util.LinkedHashMap; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ExpandableListView; import android.widget.Spinner; import android.widget.Toast; import android.widget.ExpandableListView.OnChildClickListener; import android.widget.ExpandableListView.OnGroupClickListener; public class MainActivity extends Activity implements OnClickListener{ private LinkedHashMap<String, HeaderInfo> myDepartments = new LinkedHashMap<String, HeaderInfo>(); private ArrayList<HeaderInfo> deptList = new ArrayList<HeaderInfo>(); private MyListAdapter listAdapter; private ExpandableListView myList; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Spinner spinner = (Spinner) findViewById(R.id.department); // Create an ArrayAdapter using the string array and a default spinner layout ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.dept_array, android.R.layout.simple_spinner_item); // Specify the layout to use when the list of choices appears adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // Apply the adapter to the spinner spinner.setAdapter(adapter); //Just add some data to start with loadData(); //get reference to the ExpandableListView myList = (ExpandableListView) findViewById(R.id.myList); //create the adapter by passing your ArrayList data listAdapter = new MyListAdapter(MainActivity.this, deptList); //attach the adapter to the list myList.setAdapter(listAdapter); //expand all Groups expandAll(); //add new item to the List Button add = (Button) findViewById(R.id.add); add.setOnClickListener(this); //listener for child row click myList.setOnChildClickListener(myListItemClicked); //listener for group heading click myList.setOnGroupClickListener(myListGroupClicked); } public void onClick(View v) { switch (v.getId()) { //add entry to the List case R.id.add: Spinner spinner = (Spinner) findViewById(R.id.department); String department = spinner.getSelectedItem().toString(); EditText editText = (EditText) findViewById(R.id.product); String product = editText.getText().toString(); editText.setText(""); //add a new item to the list int groupPosition = addProduct(department,product); //notify the list so that changes can take effect listAdapter.notifyDataSetChanged(); //collapse all groups collapseAll(); //expand the group where item was just added myList.expandGroup(groupPosition); //set the current group to be selected so that it becomes visible myList.setSelectedGroup(groupPosition); break; // More buttons go here (if any) ... } } //method to expand all groups private void expandAll() { int count = listAdapter.getGroupCount(); for (int i = 0; i < count; i++){ myList.expandGroup(i); } } //method to collapse all groups private void collapseAll() { int count = listAdapter.getGroupCount(); for (int i = 0; i < count; i++){ myList.collapseGroup(i); } } //load some initial data into out list private void loadData(){ addProduct("Apparel","Activewear"); addProduct("Apparel","Jackets"); addProduct("Apparel","Shorts"); addProduct("Beauty","Fragrances"); addProduct("Beauty","Makeup"); } //our child listener private OnChildClickListener myListItemClicked = new OnChildClickListener() { public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { //get the group header HeaderInfo headerInfo = deptList.get(groupPosition); //get the child info DetailInfo detailInfo = headerInfo.getProductList().get(childPosition); //display it or do something with it Toast.makeText(getBaseContext(), "Clicked on Detail " + headerInfo.getName() + "/" + detailInfo.getName(), Toast.LENGTH_LONG).show(); return false; } }; //our group listener private OnGroupClickListener myListGroupClicked = new OnGroupClickListener() { public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { //get the group header HeaderInfo headerInfo = deptList.get(groupPosition); //display it or do something with it Toast.makeText(getBaseContext(), "Child on Header " + headerInfo.getName(), Toast.LENGTH_LONG).show(); return false; } }; //here we maintain our products in various departments private int addProduct(String department, String product){ int groupPosition = 0; //check the hash map if the group already exists HeaderInfo headerInfo = myDepartments.get(department); //add the group if doesn't exists if(headerInfo == null){ headerInfo = new HeaderInfo(); headerInfo.setName(department); myDepartments.put(department, headerInfo); deptList.add(headerInfo); } //get the children for the group ArrayList<DetailInfo> productList = headerInfo.getProductList(); //size of the children list int listSize = productList.size(); //add to the counter listSize++; //create a new child and add that to the group DetailInfo detailInfo = new DetailInfo(); detailInfo.setSequence(String.valueOf(listSize)); detailInfo.setName(product); productList.add(detailInfo); headerInfo.setProductList(productList); //find the group position inside the list groupPosition = deptList.indexOf(headerInfo); return groupPosition; } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
1 comment:
How to remove/edit child items?
Post a Comment
NO JUNK, Please try to keep this clean and related to the topic at hand.
Comments are for users to ask questions, collaborate or improve on existing.