You can customize the ListView by providing a new layout for the list items “rows”. The new layout can be more than just a single TextView. Here will see how to develop a custom ListView with items having leading icons “ImageView“, trailing counters “TextView” and some text in between. Also, we will see how to add items that will act as a group header “title” for a set of other items.
Objectives:
- How to create ListView with custom View?
- How to create ListView items with leading icons “ImageView” and trailing counters?
- How to create ListView items that act as header of group of items?
Environment & Tools:
- Android Developer Tools (ADT) (or Eclipse + ADT plugin)
- AVD Nexus S Android 4.3 “emulator” or,
- Min SDK 8
( 1 ) Create Layout “UI” for ListView Items
We will define the items layout. We need two different layouts one for the target item and one for the group header item.
1. target_item.xml
2. group_header_item.xml
1. Target Item
- res/layout/target_item.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 |
<? xml version = "1.0" encoding = "utf-8" ?> android:layout_width = "match_parent" android:layout_height = "48dp" android:background = "#F3F3F3" > <!-- icon --> < ImageView android:id = "@+id/item_icon" android:layout_width = "32dp" android:layout_height = "32dp" android:layout_alignParentLeft = "true" android:layout_marginLeft = "8dp" android:layout_marginRight = "8dp" android:layout_marginTop = "8dp" android:src = "@drawable/action_help" /> <!-- title --> < TextView android:id = "@+id/item_title" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_toRightOf = "@+id/item_icon" android:layout_alignBaseline = "@+id/item_counter" android:textSize = "18dp" /> <!-- counter --> < TextView android:id = "@+id/item_counter" android:layout_width = "32dp" android:layout_height = "32dp" android:layout_alignParentRight = "true" android:layout_marginRight = "8dp" android:layout_marginTop = "8dp" android:background = "@drawable/rectangle" android:gravity = "center" android:textColor = "#FFFFFF" android:textSize = "12sp" android:textStyle = "bold" /> </ RelativeLayout > |
Note: @drawable/rectangle is defined in res/drawable/rectangle.xml
1
2
3
4
5
6 |
<? xml version = "1.0" encoding = "utf-8" ?> < solid android:color = "#5490CC" ></ solid > < corners android:radius = "8px" ></ corners > < stroke android:width = "2dp" android:color = "#A4C2E0" ></ stroke > </ shape > |
2. Group Header Item
- res/layout/group_header_item.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 |
<? xml version = "1.0" encoding = "utf-8" ?> android:layout_width = "match_parent" android:layout_height = "48dp" android:background = "#F3F3F3" > <!-- title --> < TextView android:id = "@+id/header" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:gravity = "center_vertical" android:textSize = "16dp" android:layout_marginLeft = "12dp" android:layout_marginBottom = "4dp" android:layout_alignParentBottom = "true" /> <!-- divider --> < View android:layout_width = "match_parent" android:layout_height = "1dp" android:layout_marginBottom = "1dp" android:layout_alignParentBottom = "true" android:background = "#DADADC" ></ View > </ RelativeLayout > |
( 2 ) Model.java Class “Model”
- Create a model class and call it “Model.java” to hold data to be displayed on list items.
- We need to define an object of type Model to hold the resources “data” for each list item.
- The way we define the Model object “which constructor we use” will determine which list item layout “target item or group header item” will be displayed. Basically we set the a boolean property “isGroupHeader” to be always false “if we are creating the Model object for target item layout“ unless we define the Model object “for group header item layout” using the single argument constructor then isGroupHeader will be true.
- For target_item we need a Model object to be declared as following:
new Model(R.drawable.action_help_32,"Menu Item 1","1") //R.drawable.action_help_32 is a png image in res/drawable folder
- For group_header_item we need a Model object to be declared as following:
new Model("Group Title")
- src/com/hmkcode/android/Model.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 |
package com.hmkcode.android; public class Model{ private int icon; private String title; private String counter; private boolean isGroupHeader = false ; public Model(String title) { this (- 1 ,title, null ); isGroupHeader = true ; } public Model( int icon, String title, String counter) { super (); this .icon = icon; this .title = title; this .counter = counter; } //gettters & setters... } |
( 3 ) MyAdapter.java
- MyAdpater is the class that will fill the gap between step 1 & 2 i.e. the item layout and Model data.
- MyAdapter extends ArrayAdapter<Model>
- MyAdapter(Context context, ArrayList<Model> modelsArrayList) constructor takes context i.e. “Activity” & array of objects of type Model.
- Override getView() method
- getView() method will basically go over the passed array of objects “Model”
- If the Model object isGroupHeader = false then inflate target_item, get its views, set their values and return View with target_layout
- else return View with group_header_layout.
- src/com/hmkcode/android/MyAdapter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 |
package com.hmkcode.android; import java.util.ArrayList; import com.hmkcode.android.R; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; public class MyAdapter extends ArrayAdapter<Model> { private final Context context; private final ArrayList<Model> modelsArrayList; public MyAdapter(Context context, ArrayList<Model> modelsArrayList) { super (context, R.layout.target_item, modelsArrayList); this .context = context; this .modelsArrayList = modelsArrayList; } @Override public View getView( int position, View convertView, ViewGroup parent) { // 1. Create inflater LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); // 2. Get rowView from inflater View rowView = null ; if (!modelsArrayList.get(position).isGroupHeader()){ rowView = inflater.inflate(R.layout.target_item, parent, false ); // 3. Get icon,title & counter views from the rowView ImageView imgView = (ImageView) rowView.findViewById(R.id.item_icon); TextView titleView = (TextView) rowView.findViewById(R.id.item_title); TextView counterView = (TextView) rowView.findViewById(R.id.item_counter); // 4. Set the text for textView imgView.setImageResource(modelsArrayList.get(position).getIcon()); titleView.setText(modelsArrayList.get(position).getTitle()); counterView.setText(modelsArrayList.get(position).getCounter()); } else { rowView = inflater.inflate(R.layout.group_header_item, parent, false ); TextView titleView = (TextView) rowView.findViewById(R.id.header); titleView.setText(modelsArrayList.get(position).getTitle()); } // 5. retrn rowView return rowView; } } |
( 4 ) MainActivity.java
- For MainActivity class we have two options either to extend Activity or ListActivity, comments on the code explain how to use each one.
- src/com/hmkcode/android/MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 |
package com.hmkcode.android; import java.util.ArrayList; import android.app.Activity; import android.app.ListActivity; import android.os.Bundle; import android.widget.ListView; public class MainActivity extends ListActivity { public void onCreate(Bundle icicle) { super .onCreate(icicle); // if extending Activity //setContentView(R.layout.activity_main); // 1. pass context and data to the custom adapter MyAdapter adapter = new MyAdapter( this , generateData()); // if extending Activity 2. Get ListView from activity_main.xml //ListView listView = (ListView) findViewById(R.id.listview); // 3. setListAdapter //listView.setAdapter(adapter); if extending Activity setListAdapter(adapter); } private ArrayList<Model> generateData(){ ArrayList<Model> models = new ArrayList<Model>(); models.add( new Model( "Group Title" )); models.add( new Model(R.drawable.action_help_32, "Menu Item 1" , "1" )); models.add( new Model(R.drawable.action_search_32, "Menu Item 2" , "2" )); models.add( new Model(R.drawable.collections_cloud_32, "Menu Item 3" , "12" )); return models; } } |
Run the app you will get the following UI
Icons used in this sample are downloaded from Download the Action Bar Icon Pack
Source Code @ GitHub