The preceding version of the DynamicDemo application works fine. However, sometimes ArrayAdapter cannot be used even to set up the basics of our row. For example, it is possible to have a ListView
where the rows are materially different, such as category headers
interspersed among regular rows. In that case, we may need to do all the
work ourselves, starting with inflating our rows. We will do that after
a brief introduction to inflation.
1. A Sidebar About Inflation
"Inflation" means the act of converting an XML layout specification into the actual tree of View objects the XML represents. This is undoubtedly a tedious bit of code: take an element, create an instance of the specified View
class, walk the attributes, convert those into property setter calls,
iterate over all child elements, lather, rinse, and repeat.
The good news is that the fine folks on the Android team wrapped up all that into a class called LayoutInflater, which we can use ourselves. When it comes to fancy lists, for example, we want to inflate a View
for each row shown in the list, so we can use the convenient shorthand
of the XML layout to describe what the rows are supposed to look like.
For example, let's look at a slightly different implementation of the DynamicDemo class, from the FancyLists/DynamicEx project:
public class DynamicDemo extends ListActivity {
TextView selection;
private static final String[] items={"lorem", "ipsum", "dolor",
"sit", "amet",
"consectetuer", "adipiscing", "elit", "morbi", "vel",
"ligula", "vitae", "arcu", "aliquet", "mollis",
"etiam", "vel", "erat", "placerat", "ante",
"porttitor", "sodales", "pellentesque", "augue", "purus"};
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
setListAdapter(new IconicAdapter());
selection=(TextView)findViewById(R.id.selection);
}
public void onListItemClick(ListView parent, View v,
int position, long id) {
selection.setText(items[position]);
}
class IconicAdapter extends ArrayAdapter<String> {
IconicAdapter() {
super(DynamicDemo.this, R.layout.row, items);
}
public View getView(int position, View convertView,
ViewGroup parent) {
LayoutInflaterinflater=getLayoutInflater();
View row=inflater.inflate(R.layout.row, parent, false);
TextView label=(TextView)row.findViewById(R.id.label);
label.setText(items[position]);
ImageView icon=(ImageView)row.findViewById(R.id.icon);
if (items[position].length()>4) {
icon.setImageResource(R.drawable.delete);
}
else {
icon.setImageResource(R.drawable.ok);
}
return(row);
}
}
}
Here we inflate our R.layout.row layout by use of a LayoutInflater object, obtained from our Activity via getLayoutInflater(). This gives us a View object back, which, in reality, is our LinearLayout with an ImageView and a TextView, just as R.layout.row specifies. However, rather than having to create all those objects ourselves and wire them together, the XML and LayoutInflater handle the "heavy lifting" for us.
2. And Now, Back to Our Story
So we have used LayoutInflater to give us a View
representing the row. This row is "empty," since the static layout file
has no idea what actual data goes into the row. It is our job to
customize and populate the row as we see fit before returning it, as
follows:
Fill in the text label for our label widget, using the word at the supplied position
See if the word is longer than four characters and, if so, find our ImageView icon widget and replace the stock resource with a different one
The user sees nothing
different—we have simply changed how those rows are being created.
Obviously, this was a fairly contrived example, but you can see that
this technique could be used to customize rows based on any sort of
criteria.