Android ListView with different layouts for each row
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 list
getItemViewType(int position)
- returns information which layout type you should use based on position
Then 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:
- Storing views in object called
ViewHolder
. It would increase speed because you won't have to callfindViewById()
every time ingetView
method. See List14 in API demos. - Create one generic layout that will conform all combinations of properties and hide some elements if current position doesn't have it.
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.
ListView with different layouts with two different objects
I would create a Single list of Items
public class Items {
private String time_start;
private String time_end;
private String location;
private int image;
private String locationeven;
private int oddoreven;
public String getTime_start() {
return time_start;
}
public void setTime_start(String time_start) {
this.time_start = time_start;
}
public String getTime_end() {
return time_end;
}
public void setTime_end(String time_end) {
this.time_end = time_end;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public int getImage() {
return image;
}
public void setImage(int image) {
this.image = image;
}
public String getLocationeven() {
return locationeven;
}
public void setLocationeven(String locationeven) {
this.locationeven = locationeven;
}
public int getOddoreven() {
return oddoreven;
}
public void setOddoreven(int oddoreven) {
this.oddoreven = oddoreven;
}
}
In onCreate of Activity call
generateData() ;
Then
ArrayList<Items> oddorevenlist = new ArrayList<Items>();
private void generateData() {
Items item1 = new Items();
item1.setTime_start("12:34");
item1.setTime_end("");
item1.setLocation("Aktueller Standort");
item1.setOddoreven(0);
oddorevenlist.add(item1);
Items item2 = new Items();
item2.setImage(R.drawable.ic_launcher);
item2.setLocationeven("3 Minuten Fußweg");
item2.setOddoreven(1);
oddorevenlist.add(item2);
Items item3 = new Items();
item3.setTime_start("12:37");
item3.setTime_end("12:37");
item3.setLocation("Tum");
item3.setOddoreven(0);
oddorevenlist.add(item3);
Items item4 = new Items();
item4.setImage(R.drawable.ic_launcher);
item4.setLocationeven("Richtung Hauptbahnhof Nord");
item4.setOddoreven(1);
oddorevenlist.add(item4);
Items item5 = new Items();
item5.setTime_start("12:42");
item5.setTime_end("12:42");
item5.setLocation("Hauptbahnhof Nord");
item5.setOddoreven(0);
oddorevenlist.add(item5);
Items item6 = new Items();
item6.setImage(R.drawable.ic_launcher);
item6.setLocationeven("R6 Minuten Fußweg");
item6.setOddoreven(1);
oddorevenlist.add(item6);
Items item7 = new Items();
item7.setTime_start("12:48");
item7.setTime_end("12:48");
item7.setLocation("HHauptbahnhof");
item7.setOddoreven(0);
oddorevenlist.add(item7);
MyCustomAdapter mAdapter = new MyCustomAdapter(this,oddorevenlist);
setListAdapter(mAdapter);
}
Adapter code
public class MyCustomAdapter extends BaseAdapter {
// Tag for Logging
private static final String TAG = "MyCustomAdapter";
int type;
private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;
private ArrayList<Items> oddorevenlist ;
private LayoutInflater mInflater;
private Context context;
public MyCustomAdapter(Context context, ArrayList<Items> oddorevenlist) {
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.context = context;
this.oddorevenlist = oddorevenlist;
}
@Override
public int getItemViewType(int position) {
if (oddorevenlist.get(position).getOddoreven()==0){
type = TYPE_ITEM;
} else if (oddorevenlist.get(position).getOddoreven()==1) {
type = TYPE_SEPARATOR;
}
return type;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getCount() {
return oddorevenlist.size();
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
int type = getItemViewType(position);
Log.d(TAG, "getView " + position + " " + convertView + " type = " + type);
if (convertView == null) {
holder = new ViewHolder();
switch (type) {
case TYPE_ITEM:
//inflate the new layout
convertView = mInflater.inflate(R.layout.row_odd, parent, false);
holder.tv_time_from = (TextView) convertView.findViewById(R.id.tv_time_from);
holder.tv_time_to = (TextView) convertView.findViewById(R.id.tv_time_to);
holder.tv_current_location_odd = (TextView) convertView.findViewById(R.id.tv_current_location_odd);
holder.tv_time_from.setText(oddorevenlist.get(position).getTime_start());
holder.tv_time_to.setText(oddorevenlist.get(position).getTime_end());
holder.tv_current_location_odd.setText(oddorevenlist.get(position).getLocation());
break;
case TYPE_SEPARATOR:
//inflate the new layout
convertView = mInflater.inflate(R.layout.row_even, parent, false);
holder.tv_current_location_even = (TextView) convertView.findViewById(R.id.tv_current_location_even);
holder.img_transport = (ImageView) convertView.findViewById(R.id.img_transport);
//fill the layout with values
holder.tv_current_location_even.setText(oddorevenlist.get(position).getLocationeven());
holder.img_transport.setImageResource(R.drawable.ic_launcher);
break;
default:
break;
}
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
private static class ViewHolder {
public TextView tv_time_from;
public TextView tv_time_to;
public TextView tv_current_location_odd;
public TextView tv_current_location_even;
public ImageView img_transport;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
}
Snap
Android Listview ArrayAdapter with two layouts
Android's adapter provide a way to use multiple layouts in a single adapter.
First, tell your adapter how many layouts you need:
public int getViewTypeCount()
{
return 2;
}
Then, gives some logic to tell which layout should be used for the current item:
public int getItemViewType(int position)
{
if (verses.get(position).getVerseNumber() != 0)
{
return 0;
}
return 1;
}
Finally, in your build the appropriate view:
public View getView(int position, View convertView, ViewGroup parent)
{
if (this.getItemViewType(position) == 0)
{
// TODO Build the appropriate view
return view;
}
// TODO Build the appropriate other view
return view;
}
Different row layouts in ListView
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 )
Different layout for first row of ListView in ArrayAdapter
Override getViewTypeCount()
in your adapter to return 2. Override getItemViewType()
to return 0 for position 0 and return 1 for all other positions. This teaches the ListView
that you have two different row layouts, where the first row (position 0) has a different layout than do the other rows. This will ensure that row recycling gives you back the correct row layout for your position.
Related Topics
Make a Link in the Android Browser Start Up My App
How to Retrieve the Dimensions of a View
Android Action_Image_Capture Intent
Get Visible Items in Recyclerview
Firebase Data Desc Sorting in Android
Difference Between Activity Context and Application Context
Dilemma: When to Use Fragments VS Activities:
How to Get the Build/Version Number of Your Android Application
How to Add the New "Floating Action Button" Between Two Widgets/Layouts
How to Prevent Custom Views from Losing State Across Screen Orientation Changes
How to Set a Custom Font in the Actionbar Title
Height of Status Bar in Android
How to Update a Single Row in a Listview
How to Customize the Back Button on Actionbar
Android: Show Soft Keyboard Automatically When Focus Is on an Edittext