Android: ListView animation on adding and removing item

Listview animation by AnimationListener:

This post describes how to use ListView animatation. We talked aboutListView and Custom Adapter, but an aspect we want to consider is how toanimate the ListView. In this example we will show how to animate Listview when we delete items using AnimatorListener.
As example we will use an ArrayAdapter that is populated by a large number of items. In this case we will use android.R.layout.simple_list_item_1 as row layout.
We will focus our attention on the item animation. For example we want that selected item will fade until they disappear.
The first thing we need to do is creating our animation. We will an xml file called fade_anim.xml under res/anim.
The xml file is very simple, we define that we want that our animation moves from fade 1 to fade 0 with a linear interpolator.

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="1.0" android:toAlpha="0"
android:interpolator="@android:anim/linear_interpolator"
android:duration="1000"/>

Now in the main activity we simply populate our ListView with an ArrayAdapter like:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView lv = (ListView) findViewById(R.id.listView);
List<ItemDetail> itemList = createItems(50);
final ArrayAdapter<ItemDetail> aAdpt =
new ArrayAdapter<ItemDetail>(this,
android.R.layout.simple_list_item_1, itemList);

lv.setAdapter(aAdpt);
..
}

Where createItems method simply create items like item1,item2,…
The first thing we have to load is our animation in the onCreate with:

// Load animation
final <a class="zem_slink" href="http://en.wikipedia.org/wiki/Animation" title="Animation" rel="wikipedia" target="_blank">Animation</a> anim = AnimationUtils.loadAnimation(this, R.anim.fade_anim);

Now we want to start our animation when user clicks on an item inside the ListView. But we need first run the animation and when the animation ends we have to remove item from the list. We need, then, an AnimationListenerto coordinate these phases (line 6).
So we have first create the listener and then start the animation (line 21) like:

lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView,
final View view, final int position,
long id) {
anim.setAnimationListener(new Animation.AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {
}

@Override
public void onAnimationRepeat(Animation animation) {}

@Override
public void onAnimationEnd(Animation animation) {
ItemDetail item = aAdpt.getItem(position);
aAdpt.remove(item);
}
});
view.startAnimation(anim);
}
});

Let’s run the app. If we clicks on an item we will see that it works correctly, first starts the fading animation and then the item is removed.
Come back to xml file and make the animation duration longer  (for example 3sec=3000), and run it again. While we click on an item and it starts fading let’s scroll the list.
What is happening?
Well we can notice that other items are fading even if we didn’t click them at all!! Why??
This is because OS re-use the view with other items. So we need to find a way to tell the to OS that while the item is fading the corresponding view shouldn’t be used.
How can we do it?!
Well in the onAnimationStart (line 10), when the animation is starting, we can flag the view with transient state, that tells to the OS to not re-use the view.
When the animation ends (line 20), we tell to the OS that the view can be re-used and set the transient to the default value while we set the fade value to 1.

lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView,
final View view, final int position,
long id) {
anim.setAnimationListener(new Animation.AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {
view.setHasTransientState(true);
}

@Override
public void onAnimationRepeat(Animation animation) {}

@Override
public void onAnimationEnd(Animation animation) {
ItemDetail item = aAdpt.getItem(position);
aAdpt.remove(item);
view.setHasTransientState(false);
}
});
view.startAnimation(anim);
}
});

Now everything works correctly even if we scroll the ListView while the item is fading.

Source  @ github

ListView animation by Handler:

Animation anim = AnimationUtils.loadAnimation(
                     GoTransitApp.this, android.R.anim.slide_out_right
                 );
anim.setDuration(500);
listView.getChildAt(index).startAnimation(anim );

new Handler().postDelayed(new Runnable() {

    public void run() {

        FavouritesManager.getInstance().remove(
            FavouritesManager.getInstance().getTripManagerAtIndex(index)
        );
        populateList();
        adapter.notifyDataSetChanged();

    }

}, anim.getDuration());

for top-to-down animation use :

<set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate android:fromYDelta="20%p" android:toYDelta="-20"
            android:duration="@android:integer/config_mediumAnimTime"/>
        <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
            android:duration="@android:integer/config_mediumAnimTime" />
</set>

Android: Multiple layout – Implementing a Heterogenous ListView

Overview

In certain situations, we need to implement a ListView where there are different types of rows in the same list. In other words, different items in the list need to be represented differently. Examples include a Tumblr client where each post might be an image, text or a video. Another example would be Facebook with the many different types of feed items.

To implement a heterogenous list of items, most of the work is done within the adapter. In particular, there are special methods to be overridden within an adapter such as getItemViewType, getViewTypeCount specifically for these situations.

Implementation

Suppose we wanted to implement a heterogenous list of items in an application. Keep in mind that each item in this list should be implemented with a common base model. The first step therefore is to create a model flexible enough to support all the types (i.e Post) and embed a mechanism to determine the type. Let’s pick a simple example such as list of colors in which each color is represented differently:

public class SimpleColor {
	public enum ColorValues {
		RED, BLUE, GREEN
	}

	public SimpleColor(String label, ColorValues color) {
		super();
		this.label = label;
		this.color = color;
	}

	public String label;
	public ColorValues color;

}

Here we have an enum and a field that represents the color type. We can also have additional fields and information for each type. Now, we need to create an adapter that supports this heterogenous set of colors each represented differently. The skeleton for this type of heterogenous list is a few key methods such as getViewTypeCount and getItemViewType:

public class ColorArrayAdapter extends ArrayAdapter<SimpleColor> {
    public ColorArrayAdapter(Context context, ArrayList<SimpleColor> colors) {
        super(context, 0, colors);
    }
    
    // Returns the number of types of Views that will be created by getView(int, View, ViewGroup)
    @Override
    public int getViewTypeCount() {
       // Returns the number of types of Views that will be created by this adapter
       // Each type represents a set of views that can be converted
    }
    
    // Get the type of View that will be created by getView(int, View, ViewGroup) 
    // for the specified item.
    @Override
    public int getItemViewType(int position) {
       // Return an integer here representing the type of View.
       // Note: Integers must be in the range 0 to getViewTypeCount() - 1
    }
     
    // Get a View that displays the data at the specified position in the data set. 
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       // View should be created based on the type returned from `getItemViewType(int position)`
       // convertView is guaranteed to be the "correct" recycled type
    }
}

For example, here’s how the adapter might look for an adapter responsible for creating a list of items that are represented differently based on their color:

public class ColorArrayAdapter extends ArrayAdapter<SimpleColor> {
	public ColorArrayAdapter(Context context, ArrayList<SimpleColor> colors) {
		super(context, 0, colors);
	}
         
        // Return an integer representing the type by fetching the enum type ordinal
	@Override
	public int getItemViewType(int position) {
		return getItem(position).color.ordinal();
	}
        
        // Total number of types is the number of enum values
	@Override
	public int getViewTypeCount() {
		return SimpleColor.ColorValues.values().length;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// Get the data item for this position
		SimpleColor color = getItem(position);
		// Check if an existing view is being reused, otherwise inflate the view
		if (convertView == null) {
			// Get the data item type for this position
			int type = getItemViewType(position);
			// Inflate XML layout based on the type     
			convertView = getInflatedLayoutForType(type);
		}
		// Lookup view for data population
		TextView tvLabel = (TextView) convertView.findViewById(R.id.tvLabel);
		if (tvLabel != null) {
			// Populate the data into the template view using the data object
			tvLabel.setText(color.label);
		}
		// Return the completed view to render on screen
		return convertView;
	}
        
        // Given the item type, responsible for returning the correct inflated XML layout file
	private View getInflatedLayoutForType(int type) {
		if (type == ColorValues.BLUE.ordinal()) {
			return LayoutInflater.from(getContext()).inflate(R.layout.item_blue_color, null);
		} else if (type == ColorValues.RED.ordinal()) {
			return LayoutInflater.from(getContext()).inflate(R.layout.item_red_color, null);
		} else if (type == ColorValues.GREEN.ordinal()) {
			return LayoutInflater.from(getContext()).inflate(R.layout.item_green_color, null);
		} else {
			return null;
		}
	}
}

Note that once getItemViewType is defined, the convertView object is guaranteed to be the “correct” type to ensure that recycling views is relatively straightforward. Now we can attach this together within an activity and populate a ListView with:

public class HeterogenousListActivity extends Activity {
	private ListView lvColors;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		lvColors = (ListView) findViewById(R.id.lvColors);
		ArrayList<SimpleColor> aColors = new ArrayList<SimpleColor>();
		// Populate colors into the array
		aColors.add(new SimpleColor("Blue", ColorValues.BLUE)); 
		aColors.add(new SimpleColor("Green", ColorValues.GREEN));
		// Attach the adapter
		ColorArrayAdapter adapterColors = new ColorArrayAdapter(this, aColors);
		lvColors.setAdapter(adapterColors);
	}
}

Here we’ve attached the array into an adapter and then populated the ListView as always. The result might look like this:

This is a simple example for demonstration purposes. See this article for a more detailed overview.

ViewHolder for Performance

As with any list within a production application, we will want to apply the ViewHolder Pattern for smooth scrolling by caching the subview lookups. In this case, you’ll need multiple ViewHolder classes (one per type) as outlined in this stackoverflow post.

RecyclerView and Multiple Types

RecyclerView is a newer alternative to the ListView and has a separate adapter system that works differently then the content described above. Refer to the Heterogenous Layouts Inside RecyclerView to learn more about how to render multiple item types within the RecyclerView

References

Android: Java – Checking Object Type with Instanceof

This quick lesson in our Learn Java for Android Development series shows you how to conditionally check the type of an object using the instanceof keyword in Java.

We talked about many of the basic Java conditional statements in the Learn Java for Android Development: Java Syntax tutorial. For example, Java provides all the typical conditional operators one might expect, including those to check for equality, inequality, greater than, less than, etc.

Here’s some Java code that checks the value of a numeric variable (called iVar) and provides different code paths depending on whether the value of iVar is zero, negative or positive:

Now let’s look at a specific Java feature you can also use in conditional statements. Because Java is a fully object oriented language, you can also test if an object is of a specific type (an instance of a specific class) conditionally using the instanceof keyword. The instanceof keyword is a Boolean operator, used like a regular mathematical Boolean conditional operator to generate a true or a false result.

Let’s look at a quick example. Let’s assume we have a parent class called Fish, which has two derived subclasses: SaltwaterFish and FreshwaterFish. We could use the instanceof keyword to test if an object is an instance of a specific class (or subclass) by name:

So, when it comes to Android development, when is the instanceof feature useful? Well, for starters, the Android SDK classes are organized in typical object oriented fashion: hierarchically. For example, the classes such as Button, TextView, and CheckBox, which represent different types of user interface controls, are all derived from the same parent class: View. Therefore, if you wanted to create a method that took a View parameter, but had different behavior depending upon the specific type of control, you could use theinstanceof mechanism to check the incoming parameter and determine exactly what kind of view control had been passed in.

For example, the following method takes a View parameter, allowing you to pass in any type of View, but specifically singles out TextView controls for special processing:

In this example, we might continue by making a call to a method that is only valid for a TextView object and not the generic View object—in which case, we would likely cast the View parameter to a TextView prior to making such a call. If, however, we wanted to make a call that is available in all View objects, but behaves differently in TextView objects, there is no need to test for this. Java will handle calling the appropriate version of the method specific to TextView. This is one of the great features of object-oriented programming: the most appropriate version of a given method is called.

In this quick lesson you have learned how to use the instanceof Java keyword to check the type of an object at runtime and provide conditional code paths based on the result. This is a handy Java feature that Android developers often rely upon, since the Android SDK is organized hierarchically.

Android: Multiple layout – use of getViewTypeCount() and getItemViewType() in Adapter

The use of getViewTypeCount() and getItemViewType() in Adapter:
If we need to show different type of view in list-view then its good to use  getViewTypeCount() and getItemViewType() in adapter instead of  toggling a view VIEW.GONE and VIEW.VISIBLE can be very expensive task inside getView() which will affect the list scroll.
So first of all you need to create different layouts for each type of view.
 1.simple textview.
 2.Row with image and text.
3.Simple row.
4.Row with two view .
So first need to create 4 different xmls for different row type.
Ho to use this getViewTypeCount() and getItemViewType() in adapter?
1) getViewTypeCount() :-
Returns the count of different type of views. Here we are having four different type of views so this method will return count as 4.
@Override
public int getViewTypeCount() {
return 4;
}
2) getItemViewType() :-
@Override
public int getItemViewType(int position) {

 if (mArrayList.get(position) instanceof TextModel) {
    return VIEW_TYPE_ROW_1;
 } else if (mArrayList.get(position) instanceof HeaderModel) {
    return VIEW_TYPE_ROW_2;
 } else if (mArrayList.get(position) instanceof ImageModel) {
    return VIEW_TYPE_ROW_3;
 } else {
    return VIEW_TYPE_ROW_4;
 }
}
Now Do Work inside getView(…) method first we determine the type of view by calling getItemViewType(..) method, which will return the type to be inflated as shown below.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder.MapViewHolder mapViewHolder = null;
Holder.HdrViewHolder hdrViewHolder = null;
Holder.GridViewHolder gridViewHolder = null;
Holder.BrthViewHolder brthViewHolder = null;
int type = getItemViewType(position);
if (type == VIEW_TYPE_ROW_1) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.raw_one, null);
mapViewHolder = new Holder().new MapViewHolder();
mapViewHolder.cardViewGmap = (CardView) convertView
.findViewById(R.id.list_raw_map);
convertView.setTag(mapViewHolder);
} else {
mapViewHolder = (MapViewHolder) convertView.getTag();
}
GooglePlaySmallCard cardGmap = new GooglePlaySmallCard(mContext);
cardGmap.setId(“gplaysmall”);
// Set card in the cardView
mapViewHolder.cardViewGmap.setCard(cardGmap);
} else if (type == VIEW_TYPE_ROW_2) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.raw_three, null);
hdrViewHolder = new Holder().new HdrViewHolder();
hdrViewHolder.cardshd = (CardView) convertView
.findViewById(R.id.list_carddemo_shadow_layout);
convertView.setTag(hdrViewHolder);
} else {
hdrViewHolder = (HdrViewHolder) convertView.getTag();
}
Card shcard = new Card(mContext);
// Create a CardHeader
CardHeader header = new CardHeader(mContext);
// Set the header title
header.setTitle(mContext.getString(R.string.demo_header_basetitle));
shcard.addCardHeader(header);
// Hidden shadow
shcard.setShadow(true);
hdrViewHolder.cardshd.setCard(shcard);
} else if (type == VIEW_TYPE_ROW_3) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.raw_two, null);
gridViewHolder = new Holder().new GridViewHolder();
gridViewHolder.gdcardView = (CardView) convertView
.findViewById(R.id.list_carddemo_Gplay1);
gridViewHolder.gdcardView1 = (CardView) convertView
.findViewById(R.id.list_carddemo_Gplay2);
convertView.setTag(gridViewHolder);
} else {
gridViewHolder = (GridViewHolder) convertView.getTag();
}
GplayCard gcard = new GplayCard(mContext);
gridViewHolder.gdcardView.setCard(gcard);
gridViewHolder.gdcardView1.setCard(gcard);
} else if (type == VIEW_TYPE_ROW_4) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_demo_raw, null);
brthViewHolder = new Holder().new BrthViewHolder();
brthViewHolder.bthcardView = (CardView) convertView
.findViewById(R.id.list_carddemo_cardBirth);
convertView.setTag(brthViewHolder);
} else {
brthViewHolder = (BrthViewHolder) convertView.getTag();
}
GoogleNowBirthCard birthCard = new GoogleNowBirthCard(mContext);
birthCard.setId(“myId”);
brthViewHolder.bthcardView.setCard(birthCard);
}
return convertView;
}

Android: Inflating different xml layouts in an Android ListView for different Objects.

While working on the Ambient Dynamix Project, I needed to create a listview which contains a non fixed number of headers each one followed by some list items.

A common solution is to use the MergeAdapter. A MergeAdapter object exposes the addAdapter(), addView() and addViews() methods. The demo included in the repo is pretty self explanatory.

But in case of the MergeAdapter, I’d need to keep track of multiple adapters, one for each of the list, which can be a bit of pain in case I need some data back from the adapters. So, I wrote a custom adapter which could inflate different layouts depending on the type of item.

Writing the Custom Adapter :

Create a public class which contains the types of items in the list view.

1
2
3
4
public class ListItemType {
    final public static int HEADER_VIEW = 0;
    final public static int CONTEXT_PLUGIN_VIEW = 1;
}

Create another public class with two fields, an int and an Object. We’ll use an ArrayList of objects of this class as the data source for our custom adapter. The idea is to use the use the type value to inflate the relevant xml layout inside the adapter.

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
public class ListViewItem {
    int type;
    Object object;
    public ListViewItem(int type, Object object) {
        this.type = type;
        this.object = object;
    }
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }
    public Object getObject() {
        return object;
    }
    public void setObject(Object object) {
        this.object = object;
    }
}

We’ll assume that we also have two classes whose objects contain the data for the different list items. Let’s call them HeaderObject and ListItemObject. For the sake of simplicity, we’ll just add a String field to both the classes. But you’ll need to use this method only if you have very different data for the views and hence they cannot be stored by the same object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class HeaderObject {
    String headerName;
    public HeaderObject(String headerName) {
        this.headerName = headerName;
    }
    public String getHeaderName() {
        return headerName;
    }
}
public class ListItemObject {
    String itemName;
    public ListItemObject(String itemName) {
        this.itemName = itemName;
    }
    public String getItemName() {
        return itemName;
    }
}

The custom adapter :

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class SampleAdapter extends BaseAdapter {
    Activity activity;
    ArrayList <ListViewItem> listItems;
    public SampleAdapter(Activity activity, ArrayList <ListViewItem> listItems) {
        this.activity = activity;
        this.listItems = listItems;
    }
    @Override
    public int getItemViewType(int position) {
        return installedPluginsListItems.get(position).getType();
    }
//Since we have two types of items here, we'll return 2.
    @Override
    public int getViewTypeCount() {
        return 2;
    }
//We'll use a switch case on the type and then typecast it to the relevant
// HeaderObject or the ListItemObject.
//We'll also use the ViewHolder pattern so that android can recycle the views
//and we do not inflate it every time getView() is called. We'll need to create two ViewHolder //Objects for both the item types.
//Let's assume the two layouts to inflated are called list_item_layout and header_layout.
    @Override
    public View getView(final int position, View convertView,
        final ViewGroup arg2) {
        LayoutInflater inflater = activity.getLayoutInflater();
        Object listObject = null;
        listObject = listItems
            .get(position).getObject();
        switch (getItemViewType(position)) {
            case ListItemType.CONTEXT_PLUGIN_VIEW:
                ListItemObject listItemObject = (ListItemObject) listObject;
                ViewHolderListItem holder;
                if (convertView == null) {
                    holder = new ViewHolderListItem();
                    convertView = inflater.inflate(
                            R.layout.list_item_layout, null); 
                    holder.itemNameView = (TextView) convertView.findViewById(R.id.itemNameViewId);
                    convertView.setTag(holder);
                } else {
                    holder = convertView.getTag();
                }
                holder.itemNameView.setText(listItemObject.getItemName());
                return convertView;             
            case ListItemType.HEADER_VIEW:
                HeaderObject headerObject = (HeaderObject) listObject;
                ViewHolderHeader holder;
                if (convertView == null) {
                    holder = new ViewHolderListItem();
                    convertView = inflater.inflate(
                            R.layout.header_layout, null); 
                    holder.headerNameView = (TextView) convertView.findViewById(R.id.headerNameViewId);
                    convertView.setTag(holder);
                } else {
                    holder = convertView.getTag();
                }
                holder.headerNameView.setText(headerObject.getHeaderName());
                return convertView;
        }
        return null;
    }
    private static class ViewHolderListItem {
        TextView itemNameView;
    }
    private static class ViewHolderHeader {
        TextView headerNameView;
    }
}

Creating the adapter:

1
2
3
4
5
6
ArrayList<ListViewItem> listItems = new ArrayList<>();
listItems.add(new ListViewItem(ListItemType.HEADER_VIEW, new HeaderObject(..)));
listItems.add(new ListViewItem(ListItemType.CONTEXT_PLUGIN_VIEW, new ListItemObject(..)));
listItems.add(new ListViewItem(ListItemType.CONTEXT_PLUGIN_VIEW, new ListItemObject(..)));
SampleAdapter adapter = new SampleAdapter(activity, listItems);

I am not too sure if this is the best way to go about this and there definitely is an overhead of typecasting every object but it works!

Android: Listview – Dynamically add elements to a listView Android

Create an XML layout first in your project’s res/layout/main.xml folder:

<?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" >
    <Button
        android:id="@+id/addBtn"
        android:text="Add New Item"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="addItems"/>
    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:drawSelectorOnTop="false"
    />
</LinearLayout>

This is a simple layout with a button on the top and a list view on the bottom. Note that the ListView has the id @android:id/list which defines the default ListView a ListActivity can use.

public class ListViewDemo extends ListActivity {
    //LIST OF ARRAY STRINGS WHICH WILL SERVE AS LIST ITEMS
    ArrayList<String> listItems=new ArrayList<String>();

    //DEFINING A STRING ADAPTER WHICH WILL HANDLE THE DATA OF THE LISTVIEW
    ArrayAdapter<String> adapter;

    //RECORDING HOW MANY TIMES THE BUTTON HAS BEEN CLICKED
    int clickCounter=0;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        adapter=new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1,
            listItems);
        setListAdapter(adapter);
    }

    //METHOD WHICH WILL HANDLE DYNAMIC INSERTION
    public void addItems(View v) {
        listItems.add("Clicked : "+clickCounter++);
        adapter.notifyDataSetChanged();
    }
}

android.R.layout.simple_list_item_1 is the default list item layout supplied by Android, and you can use this stock layout for non-complex things.

listItems is a List which holds the data shown in the ListView. All the insertion and removal should be done on listItems; the changes in listItems should be reflected in the view. That’s handled by ArrayAdapter<String> adapter, which should be notified using:

adapter.notifyDataSetChanged();

An Adapter is instantiated with 3 parameters: the context, which could be your activity/listactivity; the layout of your individual list item; and lastly, the list, which is the actual data to be displayed in the list.

Android code: ListView Example – Adapter, Color

Android ListView Example

Original article by Nilanchala

  1. Introduction

This post will walk you through building simple and customized ListView in Android using different Android adapters.

Scrollview is ideal for screens where scrolling is required, but it is not efficient when scroll view is used to render a larger data set. Instead you can use specialized adapter views like ListView,GridView and Recycler View (Introduced in Android Lollipop) for long lists.

  1. ListView is an Android ViewGroup, used extensively to display the collection of data in vertical scrollable rows.
  2. The list items are automatically inserted to the list using an Adapter and Adapter pulls data from data source source such as an array, cursor, etc.

2. Android Adapter

Adapter is acts as a bridge between data source and adapter views such as ListView, GridView. Adapter iterates through the data set from beginning till the end and generate Views for each item in the list.

Android SDK provides three different Adapter implementation, that includes ArrayAdapter,CursorAdapter and SimpleAdapter. An ArrayAdapter expects an Array or an List as input, while CursorAdapter accepts the instance of Cursor and SimpleAdapter maps the static data defined in the resources. The type of adapter that suits your app need is purely based on the input data type.

The BaseAdapter is the generic implementation for all of the three adapter types and can be used for ListView, GridView or for Spinners.

You may directly use ArrayAdapter by passing array as input or create your own customized class by extending BaseAdapter.

list-view-screenshots-1024x681

The image above, provides idea of customizable list views can be done using adapters.

  1. ListView Using ArrayAdapter

The simplest way for building list view is by using ArrayAdapter. Following are some of the steps used to implement simple ListView using array adapter.

  1. First step towards building list view is to identify the input data, which you want to display in list. In this example, we will be using a static array of strings.
  2. Secondly, let us declare list view in activity layout. In our example, the activity layout contains a list view inside linear layout. Provide android:id=”@+id/months_list”as ListView id.
  3. Now finally, let us instantiate the  the ArrayAdapter and set to ListView by callingsetAdapter()

Following code snippet depicts the list view declaration inside activity layout

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android&#8221;

xmlns:tools=”http://schemas.android.com/tools&#8221;

android:layout_width=”match_parent”

android:layout_height=”match_parent”

android:orientation=”vertical”>

 

<ListView

android:id=”@+id/months_list”

android:layout_width=”match_parent”

android:layout_height=”wrap_content” >

</ListView>

</LinearLayout>

Now instantiate the ListView and Array adapter. Following code snippet depicts the activity code.

ListActivity.java

import android.os.Bundle;

import android.app.Activity;

import android.widget.ArrayAdapter;

import android.widget.ListView;

 

public class ListActivity extends Activity {

private String[] monthsArray = { “JAN”, “FEB”, “MAR”, “APR”, “MAY”, “JUNE”, “JULY”,

“AUG”, “SEPT”, “OCT”, “NOV”, “DEC” };

 

private ListView monthsListView;

private ArrayAdapter arrayAdapter;

 

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_list);

 

monthsListView = (ListView) findViewById(R.id.months_list);

 

// this-The current activity context.

// Second param is the resource Id for list layout row item

// Third param is input array

arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, monthsArray);

monthsListView.setAdapter(arrayAdapter);

}

}

Output of the above code is as follows

simple-list-189x300

Download from GitHub.

  1. ListView Using Custom Adapter

So far we have created a simple list view using ArrayAdapter. Now it time to create something fancy custom a list by extending BaseAdapter. Following steps are used to implement customized ListView:

  1. First step towards building custom list is to identify the data model for each row. In our example we will display list of NewsItem
  2. Secondly, let us declare list view in activity layout.
  3. Now declare the layout for each row item.
  4. Create your custom adapter class by extending BaseAdapter
  5. Finally, let us instantiate your custom adapter and set to ListView by calling setAdapter() method.

The NewsItem object will represent each row in list. Declare NewsItem.java class and add the following code snippets.

public class NewsItem {

private String headline;

private String reporterName;

private String date;

public String getHeadline() {

return headline;

}

 

public void setHeadline(String headline) {

this.headline = headline;

}

 

public String getReporterName() {

return reporterName;

}

 

public void setReporterName(String reporterName) {

this.reporterName = reporterName;

}

 

public String getDate() {

return date;

}

 

public void setDate(String date) {

this.date = date;

}

}

4.1. Define List Row Layout

Let us create a new custom layout for list view row item containing headline, name and date TextView.

list_row_layout.xml

<?xml version=”1.0″ encoding=”utf-8″?>

<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android&#8221;

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:orientation=”horizontal”

android:padding=”5dip” >

 

<TextView

android:id=”@+id/title”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:textStyle=”bold”

android:typeface=”sans” />

 

<TextView

android:id=”@+id/reporter”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:layout_below=”@id/title”

android:layout_marginTop=”5dip”

android:textColor=”#343434″

android:textSize=”12sp” />

 

<TextView

android:id=”@+id/date”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:layout_alignBaseline=”@+id/reporter”

android:layout_alignBottom=”@+id/reporter”

android:layout_alignParentRight=”true”

android:textColor=”#343434″

android:textSize=”12sp” />

</RelativeLayout>

4.2. Custom List Adapter

Let us create a new class named CustomListAdapter.java, and extend it from BaseAdapter. You must override  the following methods form BaseAdpter class.

getCount() This method returns the total number of row counts for the listview. Typically this contains the size of the list you passing as input.
getItem() Returns object representing data for each row.
getItemId() This returns the unique integer id that represents each row item. Let us return the integer position value.
getView() The getView() method returns a view instance that represents a single row in ListView item. Here you can inflate your own layout and update values on list row.

Checkout the  following code snippets for CustomListAdapter class.

public class CustomListAdapter extends BaseAdapter {

private ArrayList<NewsItem> listData;

private LayoutInflater layoutInflater;

 

public CustomListAdapter(Context aContext, ArrayList<NewsItem> listData) {

this.listData = listData;

layoutInflater = LayoutInflater.from(aContext);

}

 

@Override

public int getCount() {

return listData.size();

}

 

@Override

public Object getItem(int position) {

return listData.get(position);

}

 

@Override

public long getItemId(int position) {

return position;

}

 

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder;

if (convertView == null) {

convertView = layoutInflater.inflate(R.layout.list_row_layout, null);

holder = new ViewHolder();

holder.headlineView = (TextView) convertView.findViewById(R.id.title);

holder.reporterNameView = (TextView) convertView.findViewById(R.id.reporter);

holder.reportedDateView = (TextView) convertView.findViewById(R.id.date);

convertView.setTag(holder);

} else {

holder = (ViewHolder) convertView.getTag();

}

 

holder.headlineView.setText(listData.get(position).getHeadline());

holder.reporterNameView.setText(“By, ” + listData.get(position).getReporterName());

holder.reportedDateView.setText(listData.get(position).getDate());

return convertView;

}

 

static class ViewHolder {

TextView headlineView;

TextView reporterNameView;

TextView reportedDateView;

}

}

4.3. Declaring ListView Layout

Declare ListView in your activity layout.

<?xml version=”1.0″ encoding=”utf-8″?>

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android&#8221;

android:layout_width=”fill_parent”

android:layout_height=”fill_parent”

android:orientation=”vertical” >

 

<ListView

android:id=”@+id/custom_list”

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:dividerHeight=”1dp” />

 

</LinearLayout>

4.4. Hooking Up to Activity

Well, we are almost ready. Let us put all of them together and hook it up to the activity. Following code snippet depicts the activity class (MainActivity.java), where we initialize Adapter and hook it up to ListView.

public class MainActivity extends Activity {

 

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

 

ArrayList image_details = getListData();

final ListView lv1 = (ListView) findViewById(R.id.custom_list);

lv1.setAdapter(new CustomListAdapter(this, image_details));

lv1.setOnItemClickListener(new OnItemClickListener() {

 

@Override

public void onItemClick(AdapterView<?> a, View v, int position, long id) {

Object o = lv1.getItemAtPosition(position);

NewsItem newsData = (NewsItem) o;

Toast.makeText(MainActivity.this, “Selected :” + ” ” + newsData, Toast.LENGTH_LONG).show();

}

});

}

 

private ArrayList getListData() {

ArrayList<NewsItem> results = new ArrayList<NewsItem>();

NewsItem newsData = new NewsItem();

newsData.setHeadline(“Dance of Democracy”);

newsData.setReporterName(“Pankaj Gupta”);

newsData.setDate(“May 26, 2013, 13:35”);

results.add(newsData);

 

// Add some more dummy data for testing

return results;

}

}

Here is the output of the above example.

customised-list-view

  1. Styling Android ListView

Like any other view, ListView in Android can customized by color, background, selection color, etc. In this section of tutorial, we will learn how to customize an Android ListView.

5.1. Changing ListView Selection Color

ListView default selection color can be changed using selectors. Selectors enables to decide how list row will visually be represented based on different states. Let us change the background and text color while list row is in pressed state.

Create a new file named list_color_selector.xml inside your drawable folder and paste the following code snippets. This selector style will be used to change the background color when list row is pressed.

<selector xmlns:android=”http://schemas.android.com/apk/res/android”&gt;

<!– Normal state. –>

<item android:drawable=”@color/list_row_default_bg”

android:state_pressed=”false”

android:state_selected=”false”/>

<!– pressed state. –>

<item android:drawable=”@color/list_row_pressed_bg”

android:state_pressed=”true”/>

<!– Selected state. –>

<item android:drawable=”@color/list_row_selected_bg”

android:state_pressed=”false”

android:state_selected=”true”/>

 

</selector>

Now, let us create file and named it as list_item_text_selector.xml. This style will be used to change the text color while list row is pressed.

<?xml version=”1.0″ encoding=”UTF-8″?>

<selector xmlns:android=”http://schemas.android.com/apk/res/android”&gt;

<item android:state_pressed=”true” android:color=”@color/text_color_inverse” />

<item android:state_focused=”true” android:color=”@color/text_color_inverse” />

<item android:color=”@color/text_color_default” />

</selector>

Define the following colors inside colors.xml file. If you don’t have colors.xml file already than create one inside values folder and paste the following code snippets.

<?xml version=”1.0″ encoding=”utf-8″?>

<resources>

<color name=”text_color_default”>#00000C</color>

<color name=”text_color_inverse”>#FFFFFF</color>

<color name=”white”>#FFFFFF</color>

<color name=”list_row_default_bg”>#ffffff</color>

<color name=”list_row_pressed_bg”>#008cef</color>

<color name=”list_row_selected_bg”>#86d3f6</color>

</resources>

Now let us apply the list selector styles to ListView inside activity_main.xml file

<ListView

android:id=”@+id/custom_list”

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:listSelector=”@drawable/list_color_selector”

android:dividerHeight=”1dp” />

Now, we can apply the styles to text in “list_row_layout.xml”. Change all TextView widget textColor attribute as shown below

<TextView

android:id=”@+id/title”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:text=””

android:textColor=”@drawable/list_item_text_selector”

android:textStyle=”bold”

android:typeface=”sans” />

Output:

android_list_example_with_list_selector

Download from GitHub.

5.2. ListView Divider Style

You can use the following properties to change the list divider styles

  1. The android:dividerproperty is used to set the list divider color. It accepts the color in#RRGGBBAA It also accepts reference to the drawable, which will be shown as list drawable.
  2. The android:dividerHeightproperty used to set the height of list divider. It can be defined in dp.

<ListView

android:id=”@+id/custom_list”

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:divider=”#FF0000″

android:dividerHeight=”1dp”

android:listSelector=”@drawable/list_selector_flatcolor” />

5.3. Changing List Divider Pragmatically

You can also change the list view divider style programmatically form java code usingsetDivider() method.

ListView listView = getListView();

ColorDrawable devidrColor = new ColorDrawable(

this.getResources().getColor(R.color.devidrColor));

listView.setDivider(devidrColor);

listView.setDividerHeight(1);

listview_row_divider_example_