2

I need to create a ListView in Android that has headers and is multiline. I use this to display the assignment title and the due date below it. The assignments are sorted under two headers: "Upcoming Assignments" and "Past Assignments" (based on date, of course).

I have the headers working and the assignment title displaying properly, but I am stumped as to how to incorporate a second line into the list.

Here is my code:

ListCourseAssignments.java

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    final SeparatedListAdapter adapter;
    setContentView(R.layout.courseassignmentslistview);
    adapter = new SeparatedListAdapter(getContext());
    ArrayAdapter<String> upcomingList = new ArrayAdapter<String>(getContext(), R.layout.list_item, Homework.getUpcomingDates()); // Homework.getUpcomingDates() Returns string array
    ArrayAdapter<String> pastList = new ArrayAdapter<String>(getContext(), R.layout.list_item, Homework.getPastDates()); // Homework.getPastDates() Returns string array

    adapter.addSection("Upcoming Assignments", upcomingList); 
    adapter.addSection("Past Assignments", pastList);

    ListView lv = (ListView) findViewById(android.R.id.list);
    lv.setAdapter(adapter);

    lv.setOnItemClickListener(new OnItemClickListener(){
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long duration){
            String item = (String) adapter.getItem(position);
            Toast.makeText(getApplicationContext(), item, Toast.LENGTH_SHORT).show();
        }
    });
}

SeparatedListAdapter.java

public class SeparatedListAdapter extends BaseAdapter {
public final Map<String, Adapter> sections = new LinkedHashMap<String, Adapter>();
public final ArrayAdapter<String> headers;

public SeparatedListAdapter(Context context) {
    headers = new ArrayAdapter<String>(context, R.layout.courseassignmentslistview_header);
}

public void addSection(String section, Adapter adapter) {
    this.headers.add(section);
    this.sections.put(section, adapter);
}

public Object getItem(int position) {
    for (Object section : this.sections.keySet()) {
        Adapter adapter = sections.get(section);
        int size = adapter.getCount() + 1;

        if (position == 0) return section;
        if (position < size) return adapter.getItem(position - 1);

        position -= size;
    }
    return null;
}

public int getCount() {
    int total = 0;
    for (Adapter adapter : this.sections.values()) total += adapter.getCount() + 1;
    return total;
}

@Override
public int getViewTypeCount() {
    int total = 1;
    for (Adapter adapter : this.sections.values()) total += adapter.getViewTypeCount();
    return total;
}

@Override
public int getItemViewType(int position) {
    int type = 1;
    for (Object section : this.sections.keySet()) {
        Adapter adapter = sections.get(section);
        int size = adapter.getCount() + 1;

        if (position == 0) return 0;
        if (position < size) return type + adapter.getItemViewType(position - 1);

        position -= size;
        type += adapter.getViewTypeCount();
    }
    return -1;
}

public boolean areAllItemsSelectable() {
    return false;
}

@Override
public boolean isEnabled(int position) {
    return (getItemViewType(position) != 0);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    int sectionnum = 0;
    for (Object section : this.sections.keySet()) {
        Adapter adapter = sections.get(section);
        int size = adapter.getCount() + 1;

        if (position == 0) return headers.getView(sectionnum, convertView, parent);
        if (position < size) return adapter.getView(position - 1, convertView, parent);

        position -= size;
        sectionnum++;
    }
    return null;
}

@Override
public long getItemId(int position) {
    return position;
}
}

courseassignmentslistview_header.xml

<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list_header_title"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:paddingTop="2dip"
    android:paddingBottom="2dip"
    android:paddingLeft="5dip"
    style="?android:attr/listSeparatorTextViewStyle" />

courseassignmentslistview.xml

<?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">

    <ListView
        android:id="@+android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

listitem.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp"
    android:textSize="16sp" >
</TextView>

Here's a screenshot of what it currently looks like.

EDIT: I know how to create a list with multiline, but I just don't know how to put it together with a list with headers (such as this)...

Kara
  • 6,115
  • 16
  • 50
  • 57
Nikhil
  • 107
  • 1
  • 5
  • http://samir-mangroliya.blogspot.in/p/android-customized-listview.html – Samir Mangroliya May 23 '12 at 03:23
  • Sorry, maybe I should have made this more clear, but adding a second line to the list is not a problem. The problem is that I can't figure out how to add a second line and have headings at the same time. Thanks for the help. – Nikhil May 23 '12 at 04:01

1 Answers1

1

I don't know how to do it with what you have so far, but you could do it with CommonWare's MergeAdapter.

Quoting the readme:

MergeAdapter accepts a mix of Adapters and Views and presents them as one contiguous 
whole to whatever ListView it is poured into. This is good for cases where you have
multiple data sources, or if you have a handful of ordinary Views to mix in with lists 
of data, or the like.

You can get it here.

I wrote a brief overview of using it here

Using MergeAdapter, you can use it to do your section headers by supplying a view for them, and then set your adapter up to create the two-line format you want.

Community
  • 1
  • 1
Barak
  • 16,318
  • 9
  • 52
  • 84
  • This looks promising. Thanks! – Nikhil May 23 '12 at 04:35
  • Okay, I'm having a little trouble. For some reason, I get a Runtime Exception and judging by the stack trace, it has nothing specifically to do with my code. "java.lang.RuntimeException You must override newView()! at com.commonsware.cwac.sacklist.SackOfViewsAdapter.newView(SackOfViewsAdapter.java:187) at com.commonsware.cwac.sacklist.SackOfViewsAdapter.getView(SackOfViewsAdapter.java:147) at com.commonsware.cwac.merge.MergeAdapter.getView(MergeAdapter.java:243) – Nikhil May 23 '12 at 05:18
  • I haven't seen that before. Looking through the docs, there's no mention of anything like that... If you contine to have problem you can post about it and CommonsWare will probably respond. He has instrutions on that repository on how to get his attention for a post on here. – Barak May 23 '12 at 05:32