coder
coder

Reputation: 13248

Android ListView with Section Headers

Please excuse me if anything mentioned here is unrelated as I am starter with android development.

I have gone through many SO questions and many examples over net explaing all the same thing but none of them suits my requirement as I need to poplulate the headers as well as list items dynamically.

Finally landed here for some good suggestions.

My Row Layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/myview"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="top"
    android:orientation="horizontal"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:paddingTop="5dp" >


    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/bg_card"
        android:orientation="horizontal" >

        <LinearLayout
            android:id="@+id/linearLayout3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >


            <TableLayout
                android:id="@+id/tableLayout4"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" >

                <TableRow
                    android:id="@+id/tableRow5"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" >

                    <TextView
                        android:id="@+id/txtTitle"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="10dp"
                        android:layout_marginStart="10dp"
                        android:layout_weight="1"
                        android:textAppearance="?android:attr/textAppearanceMedium"
                        android:textColor="#000" />

                    <TextView
                        android:id="@+id/txtTime"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="20dp"
                        android:layout_marginStart="20dp"
                        android:layout_weight="1"
                        android:textColor="#000"
                        android:textSize="24sp" />
                </TableRow>

                <TableRow
                    android:id="@+id/tableRow6"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" >

                    <TextView
                        android:id="@+id/txtCategory"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="12dp"
                        android:layout_marginStart="12dp"
                        android:layout_weight="1"
                        android:textAppearance="?android:attr/textAppearanceSmall"
                        android:textColor="#0000FF" />
                </TableRow>
            </TableLayout>
        </LinearLayout>

        <ImageView
            android:id="@+id/btndelete"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_weight="1"
            android:scaleType="fitEnd"
            android:src="@drawable/ic_menu_delete" />

    </LinearLayout>

</RelativeLayout>

This is my BaseAdapter:

  class CustomAdapter extends BaseAdapter {

    private static final int TYPE_ITEM = 0;
    private static final int TYPE_SEPARATOR = 1;

    private ArrayList<String> mData = new ArrayList<String>();
    private TreeSet<Integer> sectionHeader = new TreeSet<Integer>();

    private LayoutInflater mInflater;

    public CustomAdapter(Context context) {
        mInflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public void addItem(final String title, String category,String time) {
        mData.add(title);
        mData.add(category);
        mData.add(time);
        notifyDataSetChanged();
    }

    public void addSectionHeaderItem(final String item) {
        mData.add(item);
        sectionHeader.add(mData.size() - 1);
        notifyDataSetChanged();
    }

    @Override
    public int getItemViewType(int position) {
        return sectionHeader.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;
    }

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

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public String getItem(int position) {
        return mData.get(position);
    }

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

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        int rowType = getItemViewType(position);

        if (convertView == null) {
            holder = new ViewHolder();
            switch (rowType) {
            case TYPE_ITEM:
                //convertView = mInflater.inflate(R.layout.snippet_item1, null);
                convertView = mInflater.inflate(R.layout.adapter_listview, parent, false);
                holder.textView = (TextView) convertView.findViewById(R.id.txtTitle);
                holder.txtCategory = (TextView) convertView.findViewById(R.id.txtCategory);
                holder.txtTime = (TextView) convertView.findViewById(R.id.txtTime);
                holder.btndelete = (ImageView) convertView.findViewById(R.id.btndelete);
                break;
            case TYPE_SEPARATOR:
                //convertView = mInflater.inflate(R.layout.adapter_listview, null);
                convertView = mInflater.inflate(R.layout.snippet_item1, parent, false);
                holder.textView = (TextView) convertView.findViewById(R.id.text);
                break;
            }
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.textView.setText(mData.get(position));

        return convertView;
    }

    public static class ViewHolder {
        public TextView textView;
        public TextView txtCategory;
        public TextView txtTime;
        public ImageView btndelete;
    }

}

This is my Home Fragment:

public class HomeFragment extends Fragment  {
     @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            private CustomAdapter mAdapter;
            View rootView = inflater.inflate(R.layout.fragment_home, container, false);  
             listViewData = (ListView)rootView.findViewById(R.id.listViewData);



           return rootView;
  }

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d(TAG, "onActivityResult called");
        if((requestCode == 1)&&(resultCode == Activity.RESULT_OK)){
            if(data!= null){
                   AddedTask=data.getStringExtra("NewTask");
                   CategoryName=data.getStringExtra("CategoryItem");
                   mAdapter.addSectionHeaderItem(CategoryName);
                   mAdapter.addItem(AddedTask);
                   mAdapter.addItem(TaskTime);
                   listViewData.setAdapter(mAdapter);
                   mAdapter.notifyDataSetChanged();
      }
    }
  }
}

The result output is:

enter image description here

As you can see that I have a single row layout with all the views in it but each one is adding in each row.

The code related to that is here in my Adapter:

public void addItem(final String title, String category,String time) {
    mData.add(title);
    mData.add(category);
    mData.add(time);
    notifyDataSetChanged();
}

Now I have 2 questions here.

1. How do I change the addItem() to get the below output

enter image description here

2. How do I check if there exists a header when adding a new one and add the rest of the items below that header.

Can anyone suggest me a better way of doing this

Upvotes: 0

Views: 1248

Answers (2)

jobcrazy
jobcrazy

Reputation: 1073

Change your CustomAdapter to

  class CustomAdapter extends BaseAdapter {

private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;

private Map<String, ArrayList<String>> mData = new HashMap<String, ArrayList<String>>();

private LayoutInflater mInflater;

public CustomAdapter(Context context) {
    mInflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public void addItem(final String header, final String... contents) {
    if (mData.containsKey(header)) {
        ArrayList<String> item = new ArrayList<String>(mData.get(header));
        for(String content : contents) {
            item.add(content);
        }
        mData.remove(header);
        mData.put(header, item);
    } else {
        ArrayList<String> item = new ArrayList<String>();
        for(String content : contents) {
            item.add(content);
        }
        mData.put(header, item);
    }
    notifyDataSetChanged();
}


@Override
public int getItemViewType(int position) {
    return (position&1) == 0 ? TYPE_SEPARATOR : TYPE_ITEM;
}

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

@Override
public int getCount() {
    return mData.size() * 2;
}

@Override
public Object getItem(int position) {
    if (position&1 == 0) {
        Set<String> headers = mData.keySet();
        Iterator<String> iterator = headers.iterator();
        for (int i = 0; i < position / 2 && iterator.hasNext(); i++) {
            iterator.next();
        }
        return iterator.hasNext() ? iterator.next() : null;
    } else {
        Set<ArrayList<String>> items = mData.values();
        Iterator<ArrayList<String>> iterator = items.iterator();
        for (int i = 0; i < position / 2 && iterator.hasNext(); i++) {
            iterator.next();
        }
        return iterator.hasNext() ? iterator.next() : null;
    }
}

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

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    int rowType = getItemViewType(position);

    if (convertView == null) {
        switch (rowType) {
        case TYPE_ITEM:
            //convertView = mInflater.inflate(R.layout.snippet_item1, null);
            convertView = mInflater.inflate(R.layout.adapter_listview, parent, false);
            ArrayList<String> items = getItem(position);
            //handle your items here!
            (TextView) convertView.findViewById(R.id.txtTitle).setText()
            (TextView) convertView.findViewById(R.id.txtCategory).setText();
            (TextView) convertView.findViewById(R.id.txtTime).setText();
            (ImageView) convertView.findViewById(R.id.btndelete);
            break;
        case TYPE_SEPARATOR:
            //convertView = mInflater.inflate(R.layout.adapter_listview, null);
            convertView = mInflater.inflate(R.layout.snippet_item1, parent, false);
            (TextView) convertView.findViewById(R.id.text).setText(getItem(position));
            break;
        }
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    return convertView;
}

}

Upvotes: 1

Abdul Rahman K
Abdul Rahman K

Reputation: 664

In this code :

public void addItem(final String title, String category,String time) {
mData.add(title);
mData.add(category);
mData.add(time);
notifyDataSetChanged();
}

you are trying to add actually three items hence the result.

To get the desired Result try something like this:

class Item{
private String mTitle;
private String mCategory;
private String mTime;
public Item(String title,String time,String category){
mTitle=title;
mTime=time;
mCategory=category;
}
}

And in addItem() :

public void addItem(final String title, String category,String time) {
mData.add(new Item(title,category,time));
notifyDataSetChanged();
}

And change the BaseAdapter class to get the object of Item class from the list and hence then assign the elemnets its corresponding title, time and category

Hope it helps :)

Upvotes: 0

Related Questions