I am trying to determine the best way to have a single ListView that contains different layouts for each row. I know how to create a custom row + custom array adapter to support a custom row for the entire list view, but how can I implement many different row styles in the ListView?
Android – ListView with Different Layouts for Each Row
androidlistviewlistviewitem
Related Solutions
Implement the getItemViewType()
and getViewTypeCount()
for your adapter:
@Override
public int getViewTypeCount() {
return 2; //return 2, you have two types that the getView() method will return, normal(0) and for the last row(1)
}
and:
@Override
public int getItemViewType(int position) {
return (position == this.getCount() - 1) ? 1 : 0; //if we are at the last position then return 1, for any other position return 0
}
Then in the getView()
method find out what type of view to inflate:
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
int theType = getItemViewType(position);
if (view == null) {
ViewHolder holder = new ViewHolder();
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (theType == 0) {
// inflate the ordinary row
view = vi.inflate(R.layout.list_item_bn, null);
holder.textView = (TextView)view.findViewById(R.id.tv_name);
} else if (theType == 1){
// inflate the row for the last position
view = vi.inflate(R.layout.list_item_record, null);
holder.textView = (TextView)view.findViewById(R.id.record_view);
}
view.setTag(holder);
}
//other stuff here, keep in mind that you have a different layout for your last position so double check what are trying to initialize
}
The example from the comments: http://pastebin.com/gn65240B (or https://gist.github.com/2641914 )
That NullPointerException
occurs because you didn't implement the getItemViewType
. Right now you return the first type of row layout no matter what and this is a layout that doesn't have the *txtView_test* TextView
). Your code should be something like this:
// some fields
public static final int FIRST_TYPE = 0;
public static final int SECOND_TYPE = 1;
@Override
public int getItemViewType(int position) {
MyContents item = getItem(position);
if (item.testBoolean()) {
return FIRST_TYPE;
} else {
return SECOND_TYPE;
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final MyContents entry = content.get(position);
View row = convertView;
LayoutInflater inflater = null;
int type = getItemViewType(position);
boolean _haschild_ = entry.testBoolean();
if (row == null) {
if (type == FIRST_TYPE) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater
.inflate(R.layout.contents_layout, null);
} else {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.test_layout, null);
}
}
if (type == FIRST_TYPE) {
TextView txtView = (TextView) row
.findViewById(R.id.txtView);
//.....
} else {
((TextView) row.findViewById(R.id.txtView_test)) //**LOE**
.setText("test: " + position); //**LOE**
}
Best Answer
Since you know how many types of layout you would have - it's possible to use those methods.
getViewTypeCount()
- this methods returns information how many types of rows do you have in your listgetItemViewType(int position)
- returns information which layout type you should use based on positionThen you inflate layout only if it's null and determine type using
getItemViewType
.Look at this tutorial for further information.
To achieve some optimizations in structure that you've described in comment I would suggest:
ViewHolder
. It would increase speed because you won't have to callfindViewById()
every time ingetView
method. See List14 in API demos.I hope that will help you. If you could provide some XML stub with your data structure and information how exactly you want to map it into row, I would be able to give you more precise advise. By pixel.