Android 4
7. Advanced ListView Widget - Part B
This chapter
- 7.0 Advanced ListView
- 7.1 ListView with One Icon
- 7.2 ListView with Two Icons
- 7.3 Efficient ListView with Two Icons
- 7.4 ListView with RatingBar
- 7.5 Custom ListView - 3 subrows
- 7.6 Custom ListView with 3 Columns
- 7.7 Custom ListView with Collapsing Rows
- 7.8 Expandable ListView
In this section we will learn how we do customize ListView. Actually, we only do customize the row.
Let's preview our main code, CListView.java:
package com.bogotobogo.CListView; import java.util.ArrayList; import java.util.HashMap; import android.app.ListActivity; import android.os.Bundle; import android.widget.SimpleAdapter; public class CListViewActivity extends ListActivity { static final ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.clistview); SimpleAdapter adapter = new SimpleAdapter( this, list, R.layout.crowview, new String[] {"title","author","price"}, new int[] {R.id.text1,R.id.text2, R.id.text3} ); populateList(); setListAdapter(adapter); } private void populateList() { HashMap<String,String> map = new HashMap<String,String>(); map.put("title", "Programming Android "); map.put("author", " Zigurd Mednieks.."); map.put("price", "$44.99"); list.add(map); map = new HashMap<String,String>(); map.put("title", "The Android Developer's Cookbook: Building Applications with the Android SDK "); map.put("author", "James Steele and Nelson To "); map.put("price", "$44.99"); list.add(map); map = new HashMap<String,String>(); map.put("title","Pro Android 3 "); map.put("author", "Satya Komatineni, Dave MacLean and Sayed Hashimi "); map.put("price", "$49.99"); list.add(map); map = new HashMap<String,String>(); map.put("title", "Beginning Android Application Development (Wrox Programmer to Programmer) "); map.put("author", "Wei Meng Lee"); map.put("price", "$39.99"); list.add(map); map = new HashMap<String,String>(); map.put("title", "Learning Android"); map.put("author", "Marko Gargenta"); map.put("price", "$34.99"); list.add(map); map = new HashMap<String,String>(); map.put("title","Android for Programmers: An App-Driven Approach"); map.put("author", "Paul J. Deitel, Harvey M. Deitel, ..."); map.put("price", "$44.99"); list.add(map); map = new HashMap<String,String>(); map.put("title", "Hello, Android: Introducing Google's Mobile Development Platform"); map.put("author", " Ed Burnette"); map.put("price", "$34.99"); list.add(map); map = new HashMap<String,String>(); map.put("title", "Beginning Android Games"); map.put("author", "Mario Zechner"); map.put("price", "$39.99"); list.add(map); } }
First, let's look at the layout for ListView, clistview.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ListView android:id="@id/android:list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#bfffdf" android:drawSelectorOnTop="false"> </ListView> </LinearLayout>
We're going to have three sub-rows for each row of the ListView. So, layout file for each row crowview.xml should look like this:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/text1" android:textSize="18sp" android:textStyle="bold" android:textColor="#000000" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <TextView android:id="@+id/text2" android:textSize="10sp" android:textStyle="italic" android:textColor="#00cd00" android:layout_width="wrap_content" android:layout_height="fill_parent"/> <TextView android:id="@+id/text3" android:typeface="sans" android:textSize="14sp" android:textStyle="bold" android:textColor="#0000ff" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>
Note that we defined three TextViews for the three sub-rows.
So, we have the display layout. Let's look at the main code how it works.
Our activity is extending ListActivity.
public class CListViewActivity extends ListActivity {
We are using a SimpleAdpater provided by the SDK. This adapter needs the context, the layout and the handle to the data that we want to display
SimpleAdapter adapter = new SimpleAdapter( this< list< R.layout.crowview< new String[] {"title"<"author"<"price"}< new int[] {R.id.text1<R.id.text2< R.id.text3} );
Actually, before passing the array, we declare a list of data in an ArrayList of HashMaps.
static final ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
Then, we populate it.
private void populateList() { HashMap<String,String> map = new HashMap<String,String>(); map.put("title", "Programming Android "); map.put("author", " Zigurd Mednieks.."); map.put("price", "$44.99"); list.add(map); .......
Finally, setListAdapter(adapter) automatically adds our ListView to fill the entire screen of the ListActivity.
Let's run our Customized ListView.
Files used in this Customized ListView example CListView.zip
Custom Listview with 3 columns is not much different from the previous example with 3 subrows in terms of implementation.
Here is the main Java code, CListView2.java:
package com.bogotobogo.android.clistview2; import java.util.ArrayList; import java.util.HashMap; import android.app.ListActivity; import android.os.Bundle; import android.widget.SimpleAdapter; public class CListView2 extends ListActivity { static final ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.clistview); SimpleAdapter adapter = new SimpleAdapter( this, list, R.layout.crowview, new String[] {"rank","model","company"}, new int[] {R.id.text1,R.id.text2, R.id.text3} ); populateList(); setListAdapter(adapter); } private void populateList() { HashMapmap = new HashMap (); map.put("rank", "1"); map.put("model", "Samsung Galaxy Nexus"); map.put("company", "Samsung"); list.add(map); map = new HashMap (); map.put("rank", "2"); map.put("model", "Samsung Epic Touch 4G"); map.put("company", "Samsung"); list.add(map); map = new HashMap (); map.put("rank", "3"); map.put("model", "HTC Evo 3D"); map.put("company", "HTC"); list.add(map); map = new HashMap (); map.put("rank", "4"); map.put("model", "T-Mobile MyTouch 4G Slide"); map.put("company", "HTC"); list.add(map); map = new HashMap (); map.put("rank", "5"); map.put("model", "Samsung Galaxy S II"); map.put("company", "Samsung"); list.add(map); map = new HashMap (); map.put("rank", "6"); map.put("model", "Apple iPhone 4S 16GB"); map.put("company", "Apple"); list.add(map); map = new HashMap (); map.put("rank", "7"); map.put("model", "Motorola Droid Razr"); map.put("company", "Motorola"); list.add(map); map = new HashMap (); map.put("rank", "8"); map.put("model", "Motorola Droid Bionic"); map.put("company", "Motorola"); list.add(map); map = new HashMap (); map.put("rank", "9"); map.put("model", "Samsung Focus S"); map.put("company", "Samsung "); list.add(map); map = new HashMap (); map.put("rank", "10"); map.put("model", "Samsung Focus Flash"); map.put("company", "Samsung"); list.add(map); } }
The main layout for the list clistview.xml:
<?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@id/android:list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#bfffdf" android:drawSelectorOnTop="false"> </ListView>
The view for 3 columns for each row is specified in crowview.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:paddingTop="4dip" android:paddingBottom="6dip" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/text1" android:textColor="#00ff00" android:textSize="18sp" android:layout_width="30dip" android:layout_height="wrap_content"/> <TextView android:id="@+id/text2" android:textColor="#ff0000" android:textSize="18sp" android:layout_width="110dip" android:layout_height="wrap_content" android:layout_weight="1"/> <TextView android:id="@+id/text3" android:textColor="#0000ff" android:textSize="14sp" android:layout_width="40dip" android:layout_height="wrap_content" android:layout_weight="1"/> </LinearLayout>
Note that in the XML for each row, we put three TextViews in LinearLayout with horizontal orientation not vertical:
<LinearLayout ..... android:orientation="horizontal">
Let's run another Customized ListView.
Files used in this Customized ListView example CListView2.zip
This example shows detail information of the phone when it is clicked.
Let's look at our Java code, CListView3.java:
package com.bogotobogo.CListView3; import android.app.ListActivity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; /** * A list view example where the * data comes from a custom ListAdapter */ public class CListView3Activity extends ListActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Use our own list adapter setListAdapter(new PhoneListAdapter(this)); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { ((PhoneListAdapter)getListAdapter()).toggle(position); } /** * A sample ListAdapter that presents content * from arrays of phones and text. */ private class PhoneListAdapter extends BaseAdapter { public PhoneListAdapter(Context context) { mContext = context; } /** * The number of items in the list is determined * by the number of phones in our array. */ public int getCount() { return mPhones.length; } /** * Since the data comes from an array, just returning * the index is sufficient to get at the data. If we * were using a more complex data structure, we * would return whatever object represents one * row in the list. */ public Object getItem(int position) { return position; } /** * Use the array index as a unique id. */ public long getItemId(int position) { return position; } /** * Make a PhoneView to hold each row. */ public View getView(int position, View convertView, ViewGroup parent) { PhoneView sv; if (convertView == null) { sv = new PhoneView (mContext, mPhones[position], mDetail[position], mExpanded[position]); } else { sv = (PhoneView)convertView; sv.setName(mPhones[position]); sv.setDetail(mDetail[position]); sv.setExpanded(mExpanded[position]); } return sv; } public void toggle(int position) { mExpanded[position] = !mExpanded[position]; notifyDataSetChanged(); } /** * Remember our context so we can use it when constructing views. */ private Context mContext; /** * Our data for names of phones, part 1. */ private String[] mPhones = { "Samsung Galaxy Nexus ", "Samsung Galaxy S II Skyrocket ", "Motorola Droid Razr ", "Apple iPhone 4S ", "HTC Rezound " }; /** * Our data for the detail description of each phone, part 2. */ private String[] mDetail = { "The Samsung Galaxy Nexus is a big step forward for Android, " + "but it's not the giant leap you may have been expecting." + "As impressive as it is, Ice Cream Sandwich can be messy, " + "and without it, the Galaxy Nexus is just another Nexus device.", "If you live in an area that gets AT&T;'s LTE network, " + "we highly recommend the powerful and beautiful ' +" + "Samsung Galaxy S II Skyrocket.", "With its razor-thin design, jam-packed features, " + "and blazing speed, the Motorola Droid Razr is " + "easily one of the year's top Android smartphones.", "The iPhone 4S isn't the king of cell phones, " + "but it's part of the royal family nonetheless.' +" + "Even without 4G and a giant screen, this phone's smart " + "voice assistant, Siri, the benefits of iOS 5, " + "and its spectacular camera make it a top choice " + "for anyone ready to upgrade.", "While it may have a hefty build, the HTC " + "Rezound's beautiful display, commendable performance ," + "and multimedia-rich features make it a top phone " + "for Verizon customers." }; /** * Our data, part 3. */ private boolean[] mExpanded = { false, false, false, false, false, false, false, false }; } /** * We will use a PhoneView to display each phone. * It's just a LinearLayout with two text fields. */ private class PhoneView extends LinearLayout { public PhoneView(Context context, String name, String detail, boolean expanded) { super(context); this.setOrientation(VERTICAL); // Here we build the child views in code. They could also have // been specified in an XML file. mPhone = new TextView(context); mPhone.setText(name); addView(mPhone, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); mDetail = new TextView(context); mDetail.setText(detail); addView(mDetail, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); mDetail.setVisibility(expanded ? VISIBLE : GONE); } /** * Convenience method to set the name of a PhoneView */ public void setName(String name) { mPhone.setText(name); } /** * Convenience method to set the detail of a PhoneView */ public void setDetail(String words) { mDetail.setText(words); } /** * Convenience method to expand or hide the detail */ public void setExpanded(boolean expanded) { mDetail.setVisibility(expanded ? VISIBLE : GONE); } private TextView mPhone; private TextView mDetail; } }
We are using our PhoneView to display each phone. It's a LinearLayout with two text fields.
The comments inside code are self-explanatory.
So, we will just run this Collapsing Customized ListView.
Files used in this Customized ListView example CListView3.zip
In this example, we subclass ExpandableListActivity to demonstrate expandable list. We use an adapter, ExpandableListAdapter which is a Simple Map-based adapter.
Here is our Java code, SmplExpandable.java:
package com.bogotobogo.android.smplexpandable; import android.app.ExpandableListActivity; import android.os.Bundle; import android.widget.ExpandableListAdapter; import android.widget.SimpleExpandableListAdapter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Demonstrates expandable lists backed by a Simple Map-based adapter */ public class SmplExpandable extends ExpandableListActivity { private static final String NAME = "NAME"; private static final String IS_EVEN = "IS_EVEN"; private ExpandableListAdapter mAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); List<Map<String, String>> groupData = new ArrayList<Map<String, String>>(); List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>(); for (int i = 0; i < 10; i++) { Map<String, String> curGroupMap = new HashMap<String, String>(); groupData.add(curGroupMap); curGroupMap.put(NAME, "Group " + i); curGroupMap.put(IS_EVEN, (i % 2 == 0) ? "This group is even" : "This group is odd"); List<Map<String, String>> children = new ArrayList<Map<String, String>>(); for (int j = 0; j < 3; j++) { Map<String, String> curChildMap = new HashMap<String, String>(); children.add(curChildMap); curChildMap.put(NAME, "Child " + j); curChildMap.put(IS_EVEN, (j % 2 == 0) ? "This child is even" : "This child is odd"); } childData.add(children); } // Set up our adapter mAdapter = new SimpleExpandableListAdapter( this, groupData, android.R.layout.simple_expandable_list_item_1, new String[] { NAME, IS_EVEN }, new int[] { android.R.id.text1, android.R.id.text2 }, childData, android.R.layout.simple_expandable_list_item_2, new String[] { NAME, IS_EVEN }, new int[] { android.R.id.text1, android.R.id.text2 } ); setListAdapter(mAdapter); } }
Files used in this expandable ListView example SmplExpandable.zip
Previous sections:
- 7.0 Advanced ListView
- 7.1 ListView with One Icon
- 7.2 ListView with Two Icons
- 7.3 Efficient ListView with Two Icons
- 7.4 ListView with RatingBar
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization