How to add multiple header views in a ListView
Asked Answered
I

3

6

I've a custom adapter for my ListView I want to add project names as the headers to my work requests. Adding a single header works just fine but I'm not sure how to add multiple headers using addHeaderView. I don't understand where exactly to place setAdapter or is it supposed to be placed multiple times?

This is my java code for a single header which works:

mListView = (ListView)findViewById(R.id.dashboardList);
View header1 =  getLayoutInflater().inflate(R.layout.listview_header, null, false);
tv = (TextView) header1.findViewById(R.id.listHeader);
adapter = new MyCustomAdapter(MyDashboardActivity.this, R.layout.mydashboard_row, dashboardBean);
tv.setText("Project 1");
mListView.addHeaderView(header1, null, false);
for (int i=0; i < 7; i++) {
     dashboardBean.add(new DashboardBean(workRequests[i],status[i],actualHours[i]));
}
mListView.setAdapter(adapter);

Now, I for two headers I tried this:

mListView = (ListView)findViewById(R.id.dashboardList);
View header1 =  getLayoutInflater().inflate(R.layout.listview_header, null, false);
tv = (TextView) header1.findViewById(R.id.listHeader);
adapter = new MyCustomAdapter(MyDashboardActivity.this, R.layout.mydashboard_row, dashboardBean);
tv.setText("RxOffice");
mListView.addHeaderView(header1, null, false);
for (int i=0; i < 4; i++) {
     dashboardBean.add(new DashboardBean(workRequests[i],status[i],actualHours[i])); 
}

tv.setText(Project 2");

mListView.addHeaderView(header1, null, false);
for (int i=4; i < workRequests.length; i++) {
     dashboardBean.add(new DashboardBean(workRequests[i],status[i],actualHours[i]));
}
mListView.setAdapter(adapter);

But this doesn't work! It gives me only the Project 2 header and all 7 entries below it. Could anyone please tell me what's wrong? I'm guessing it has something to do with setAdapter. Thanks!

Intervenient answered 25/6, 2012 at 20:58 Comment(0)
C
11

I don't think what you want to do is possible the way you are trying to do it. When you use addHeaderView it wraps your ListAdapter in HeaderViewListAdapter. I looked at the docs for it here and that seems to imply that you could have multiple headers, but they would all be at the top (duh, header).

It sounds like what you actually want is seperators...

You could use CommonWare's MergeAdapter. It will let you insert adapters and views (in whatever order you wish) and present them all as a single adapter to a listview. You just hand it headers and adapters for each section of content and then set it to your list.

Pseudo-code example:

myMergeAdapter = new MergeAdapter(); 
myMergeAdapter.addView(HeaderView1); 
myMergeAdapter.addAdapter(listAdapter1); 
myMergeAdapter.addView(HeaderView2); 
myMergeAdapter.addAdapter(listAdapter2); 
setListAdapter(myMergeAdapter); 
Chitarrone answered 26/6, 2012 at 4:29 Comment(0)
E
2

I achieved multiple header scenario using custom Section Adapter which is originally coded by CommonsWare, you can make section within listivew, like Books, Games and etc. check out below code.

Section Adapter:

package com.medplan.db;

import java.util.ArrayList;
import java.util.List;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.BaseAdapter;




abstract public class SectionedAdapter extends BaseAdapter {

    String TAG = "========SectionedAdapter============";

abstract protected View getHeaderView(String caption,
                                      int index,
                                      View convertView,
                                      ViewGroup parent);

private List<Section> sections=new ArrayList<Section>();
private static int TYPE_SECTION_HEADER=0;

public SectionedAdapter() {
  super();
  sections.clear();


}

public void addSection(String caption, Adapter adapter) {

  sections.add(new Section(caption, adapter));
}


public void clear() {

    sections.clear();
    notifyDataSetChanged();
}


public Object getItem(int position) {
  for (Section section : this.sections) {
    if (position==0) {
      return(section);
    }

    int size=section.adapter.getCount()+1;

    if (position<size) {
      return(section.adapter.getItem(position-1));
    }

    position-=size;
  }

  return(null);
}

public int getCount() {
  int total=0;

  for (Section section : this.sections) {
    total+=section.adapter.getCount()+1; // add one for header
  }

  return(total);
}

public int getViewTypeCount() {
  int total=1;  // one for the header, plus those from sections

  for (Section section : this.sections) {
    total+=section.adapter.getViewTypeCount();
  }

  return(total);
}

public int getItemViewType(int position) {
  int typeOffset=TYPE_SECTION_HEADER+1; // start counting from here

  for (Section section : this.sections) {
    if (position==0) {
      return(TYPE_SECTION_HEADER);
    }

    int size=section.adapter.getCount()+1;

    if (position<size) {
      return(typeOffset+section.adapter.getItemViewType(position-1));
    }

    position-=size;
    typeOffset+=section.adapter.getViewTypeCount();
  }

  return(-1);
}

public boolean areAllItemsSelectable() {
  return(false);
}

public boolean isEnabled(int position) {
  return(getItemViewType(position)!=TYPE_SECTION_HEADER);
}

public View getView(int position, View convertView,
                    ViewGroup parent) {
  int sectionIndex=0;

  for (Section section : this.sections) {
    if (position==0) {
      return(getHeaderView(section.caption, sectionIndex,
                            convertView, parent));
    }

    int size=section.adapter.getCount()+1;

    if (position<size) {
      return(section.adapter.getView(position-1,convertView,parent));
    }

    position-=size;
    sectionIndex++;
  }

  return(null);
}

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

class Section {
  String caption = null;
  Adapter adapter = null;

  Section(String caption, Adapter adapter) {
    this.caption=caption;
    this.adapter=adapter;
  }
}
}

Within Activity make Section adapter object,check out below code:

final SectionedAdapter adapter =new SectionedAdapter()
                {

                      protected View getHeaderView(String caption, int index, View convertView,ViewGroup parent) 
                      {

                        result=(TextView)convertView;

                        if (convertView==null) 
                        {
                          result=(TextView)getLayoutInflater().inflate(R.layout.section_header,null);

                        }

                        result.setText(caption);
                       // temp=caption;
                       // ind=index;

                        return(result);
                      }
                    };

section_header.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="wrap_content"  
    android:background="@color/black"
    android:textColor="#FFFFFF"
    android:ellipsize="end"
    android:textSize="11sp"
    style="?android:attr/listSeparatorTextViewStyle" />


<!--    android:background="#515050"-->

Within Activity add section as many as you want like below:

Note: userPic & medPic are name of arraylist.

adapter.addSection("section first", new EfficientAdapter(getApplicationContext(),usersPic)); 


adapter.addSection("section second", new EfficientAdapter(getApplicationContext(),medPic));

listview.setAdapter(adapter);
Epperson answered 26/6, 2012 at 5:36 Comment(1)
I had read about it. I wanted to know if I could do it without using MergeAdapter. Turns out I can't. ThanksIntervenient
E
0

I would solve this issue with ExpandableListView. It doesn't require any extra library.

  • Create your custom adapter.
  • Give your data and fill the methods you need to override.
  • After setting the adapter with ExpandableListView:
    • Override groupItemClick so clicking on the groups won't actually expand the view.
    • Loop through every parent in adapter and set them expanded.
Evaevacuant answered 14/8, 2015 at 13:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.