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.