Custom ListView with Date as SectionHeader (Used custom SimpleCursorAdapter)

Kartik Domadiya picture Kartik Domadiya · Jun 7, 2011 · Viewed 19.7k times · Source

I want to display ListView with Date as SectionHeader.

What i have : I am displaying ListView from sqlite database using custom SimpleCursorAdapter.

My Custom SimpleCursorAdapter is :

public class DomainAdapter extends SimpleCursorAdapter{
private Cursor dataCursor;

private LayoutInflater mInflater;

public DomainAdapter(Context context, int layout, Cursor dataCursor, String[] from,
        int[] to) {
    super(context, layout, dataCursor, from, to);
        this.dataCursor = dataCursor;
        mInflater = LayoutInflater.from(context);
}


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

    ViewHolder holder;

    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.todo_row, null);

        holder = new ViewHolder();
        holder.text1 = (TextView) convertView.findViewById(R.id.label);//Task Title
        holder.text2 = (TextView) convertView.findViewById(R.id.label2);//Task Date
        holder.img =   (ImageView) convertView.findViewById(R.id.task_icon);

        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    dataCursor.moveToPosition(position);
    int title = dataCursor.getColumnIndex("title"); 
    String task_title = dataCursor.getString(title);

    int title_date = dataCursor.getColumnIndex("day"); 
    String task_day = dataCursor.getString(title_date);

    int description_index = dataCursor.getColumnIndex("priority"); 
    int priority = dataCursor.getInt(description_index);

    holder.text1.setText(task_title);
    holder.text2.setText(task_day);

    if(priority==1) holder.img.setImageResource(R.drawable.redbutton);
    else if(priority==2) holder.img.setImageResource(R.drawable.bluebutton);
    else if(priority==3)holder.img.setImageResource(R.drawable.greenbutton);
    else holder.img.setImageResource(R.drawable.redbuttonchecked);

    return convertView;
}

static class ViewHolder {
    TextView text1;
    TextView text2;
    ImageView img;
}
}

Google Results so far :

MergeAdapter

Jeff Sharkey

Amazing ListView

SO Question

Problem : I want to display listview with Date as section headers. Ofcourse Date values come from sqlite database.

Can anyone please guide me how can i achieve this task.

Or Provide me a Sample Code or Exact(like) Code related to the same.

Edited According to Graham Borald's Answer (This works fine. However it was a quick fix.)

public class DomainAdapter extends SimpleCursorAdapter{
    private Cursor dataCursor;
    private LayoutInflater mInflater;

    public DomainAdapter(Context context, int layout, Cursor dataCursor, String[] from,
            int[] to) {
        super(context, layout, dataCursor, from, to);
            this.dataCursor = dataCursor;
            mInflater = LayoutInflater.from(context);
    }

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

        ViewHolder holder;

        if (convertView == null) 
        {
            convertView = mInflater.inflate(R.layout.tasks_row, null);
            holder = new ViewHolder();
            holder.text1 = (TextView) convertView.findViewById(R.id.label);//Task Title
            holder.text2 = (TextView) convertView.findViewById(R.id.label2);//Task Date
            holder.img =   (ImageView) convertView.findViewById(R.id.taskImage);

            holder.sec_hr=(TextView) convertView.findViewById(R.id.sec_header);

            convertView.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) convertView.getTag();
        }

        dataCursor.moveToPosition(position);
        int title = dataCursor.getColumnIndex("title"); 
        String task_title = dataCursor.getString(title);

        int title_date = dataCursor.getColumnIndex("due_date"); 
        String task_day = dataCursor.getString(title_date);

        int description_index = dataCursor.getColumnIndex("priority"); 
        int priority = dataCursor.getInt(description_index);

        String prevDate = null;

        if (dataCursor.getPosition() > 0 && dataCursor.moveToPrevious()) {
            prevDate = dataCursor.getString(title_date);
            dataCursor.moveToNext();
        }


        if(task_day.equals(prevDate))
        {
            holder.sec_hr.setVisibility(View.GONE);
        }
        else
        {
            holder.sec_hr.setText(task_day);
            holder.sec_hr.setVisibility(View.VISIBLE);
        }

        holder.text1.setText(task_title);
        holder.text2.setText(task_day);

        if(priority==1) holder.img.setImageResource(R.drawable.redbutton);
        else if(priority==2) holder.img.setImageResource(R.drawable.bluebutton);
        else if(priority==3)holder.img.setImageResource(R.drawable.greenbutton);
        else holder.img.setImageResource(R.drawable.redbuttonchecked);

        return convertView;
    }

    static class ViewHolder {
        TextView text1;
        TextView text2;
        TextView sec_hr;
        ImageView img;
    }
}

Edited According to CommonsWare's Answer

public class DomainAdapter extends SimpleCursorAdapter{
        private Cursor dataCursor;
        private TodoDbAdapter adapter;

        private LayoutInflater mInflater;
        boolean header;
      String last_day;
      public DomainAdapter(Context context, int layout, Cursor dataCursor, String[] from,
        int[] to) {
        super(context, layout, dataCursor, from, to);
        this.dataCursor = dataCursor;
        mInflater = LayoutInflater.from(context);
        header=true;
        adapter=new TodoDbAdapter(context);
}


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

    ViewHolder holder = null;
    TitleHolder title_holder = null;

    if(getItemViewType(position)==1)
    {
        //convertView= mInflater.inflate(R.layout.todo_row, parent, false);

        if (convertView == null) 
        {
            convertView = mInflater.inflate(R.layout.todo_row, null);

            holder = new ViewHolder();
            holder.text1 = (TextView) convertView.findViewById(R.id.label);//Task Title
            holder.text2 = (TextView) convertView.findViewById(R.id.label2);//Task Date
            holder.img =   (ImageView) convertView.findViewById(R.id.task_icon);

            convertView.setTag(holder);
        }
        else 
        {
            holder = (ViewHolder) convertView.getTag();
        }

        dataCursor.moveToPosition(position);
        int title = dataCursor.getColumnIndex("title"); 
        String task_title = dataCursor.getString(title);

        int title_date = dataCursor.getColumnIndex("day"); 
        String task_day = dataCursor.getString(title_date);

        int description_index = dataCursor.getColumnIndex("priority"); 
        int priority = dataCursor.getInt(description_index);

        holder.text1.setText(task_title);
        holder.text2.setText(task_day);

        if(priority==1) holder.img.setImageResource(R.drawable.redbutton);
        else if(priority==2) holder.img.setImageResource(R.drawable.bluebutton);
        else if(priority==3)holder.img.setImageResource(R.drawable.greenbutton);
        else holder.img.setImageResource(R.drawable.redbuttonchecked);
    }
    else
    {

        if (convertView == null) 
        {
            convertView = mInflater.inflate(R.layout.section_header, null);

            title_holder = new TitleHolder();
            title_holder.datee = (TextView) convertView.findViewById(R.id.sec_header);//Task Title

            convertView.setTag(title_holder);
        }
        else 
        {
            title_holder = (TitleHolder) convertView.getTag();
        }

        dataCursor.moveToPosition(position);

        int title_date = dataCursor.getColumnIndex("day"); 
        String task_day = dataCursor.getString(title_date);

        title_holder.datee.setText(task_day);
    }

    return convertView;
}

static class ViewHolder {
    TextView text1;
    TextView text2;
    ImageView img;
}

 static class TitleHolder{
    TextView datee;
}


@Override
public int getCount() {
    return dataCursor.getCount()+1; //just for testing i took no. of headers=1
}


@Override
public int getViewTypeCount() {
    return 2;
}

@Override
public int getItemViewType(int position) {

    dataCursor.moveToPosition(position);
    **Long id=dataCursor.getLong(position);**
    Cursor date=adapter.fetchTodo(id);
    int title_date = date.getColumnIndex("day"); 
        String task_day = date.getString(title_date);
        Log.i("tag",task_day);

    if(last_day.equals(task_day))
        return 1;//Display Actual Row
    else
    {
        last_day=task_day;//Displaying Header
        return 0;
    }

}

/*
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {

    final View view;

    if(getItemViewType(cursor.getPosition())==1)
        view= mInflater.inflate(R.layout.todo_row, parent, false);
    else
        view=mInflater.inflate(R.layout.section_header,parent, false);

    return view;

}

@Override
public void bindView(View convertView, Context context, Cursor cursor) {
    long id = cursor.getPosition();

}*/
}

I am getting Null Pointer Exception at line : Cursor date=adapter.fetchTodo(id); Seems that Cursor is not getting any data.

Answer

Graham Borland picture Graham Borland · Jun 8, 2011

By far the simplest way to do this is to embed the date header view in every item. Then, all you need to do in bindView is compare the previous row's date to this row's date, and hide the date if it's the same. Something like this:

    String thisDate = cursor.getString(dateIndex);
    String prevDate = null;

    // get previous item's date, for comparison
    if (cursor.getPosition() > 0 && cursor.moveToPrevious()) {
        prevDate = cursor.getString(dateIndex);
        cursor.moveToNext();
    }

    // enable section heading if it's the first one, or 
    // different from the previous one
    if (prevDate == null || !prevDate.equals(thisDate)) {
        dateSectionHeaderView.setVisibility(View.VISIBLE);
    } else {
        dateSectionHeaderView.setVisibility(View.GONE);
    }