46

I'm trying to create a custom cursoradapter that will use two different layouts depending on some data in the cursor. I keep reading about 'overriding getViewTypeCount() and getItemViewType()' to make this happen but I can't seem to figure out how to implement this..

This is my code for the bindView and new View methods:

@Override
public void bindView(View view, Context context, Cursor cursor) {
    TextView tView = (TextView) view.findViewById(R.id.TextView1);
    tView.setText("The text");
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    return mInflater.inflate(R.layout.item1, parent, false);
}

.

EDIT: Now I got this working, but I want to choose what rowlayout to use depending on some data in the cursor and I can't get that working.. anybody got some ideas?

@Override
public int getItemViewType(int position) {
    return position % 2;
}

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

@Override
public void bindView(View view, Context context, Cursor cursor) {
    ViewHolder holder = (ViewHolder) view.getTag();
    holder.txtAddress
            .setText("blabla");
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    ViewHolder holder = new ViewHolder();
    View v = null;
    int type = cursor.getPosition() % 2;
    if(type == 0) {
        v = mInflater.inflate(R.layout.item, parent, false); 
    } else {
        v = mInflater.inflate(R.layout.item2, parent, false);
    }

    holder.txtAddress = (TextView) v.findViewById(R.id.tvName);

    v.setTag(holder);
    return v;
}
Jap Mul
  • 17,398
  • 5
  • 55
  • 66
  • Are you trying to add sections/headers to your list view? Mark Murphy made a really easy to use cwac-merge list adapter that may help. – csaunders Dec 12 '11 at 20:44
  • No, i have 2 different layouts and sometimes I want to use layout1 if mCursor.getString(mCursor.getColumnIndex("type")).equals("1") and I want to use layout2 when mCursor.getString(mCursor.getColumnIndex("type")).equals("2") – Jap Mul Dec 12 '11 at 20:55
  • If you wanted, you could just grab two separate cursors. One where type == 1 and one for where type == 2. It's ghetto, but it may help you move forward. – csaunders Dec 13 '11 at 19:28

3 Answers3

94

So I finally got it work. For the ones interested the working code is below:

private int getItemViewType(Cursor cursor) {
    String type = cursor.getString(cursor.getColumnIndex("type"));
    if (type.equals("1")) {
        return 0;
    } else {
        return 1;
    }
}

@Override
public int getItemViewType(int position) {
    Cursor cursor = (Cursor) getItem(position);
    return getItemViewType(cursor);
}

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

@Override
public void bindView(View view, Context context, Cursor cursor) {
    ViewHolder holder = (ViewHolder) view.getTag();
    holder.textView
            .setText(cursor.getString(cursor.getColumnIndex("body")));
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    ViewHolder holder = new ViewHolder();
    View v = null;

    if (cursor.getString(cursor.getColumnIndex("type")).equals("1")) {
        v = mInflater.inflate(R.layout.message1, parent, false);
        holder.textView = (TextView) v
                .findViewById(R.id.textView1);
    } else {
        v = mInflater.inflate(R.layout.message2, parent, false);
        holder.textView = (TextView) v
                .findViewById(R.id.textView2);
    }

    v.setTag(holder);
    return v;
}

public static class ViewHolder {
    public TextView textView;
}
Jap Mul
  • 17,398
  • 5
  • 55
  • 66
  • getItem(position) calls moveToPosition(position) on the internal cursor object, and I suspect it to be a little too expensive to be called so often. Do you get it to scroll fluently with this in your app? – Håvard Geithus Jun 23 '12 at 16:33
  • 2
    Yep scrolls fluently. Found code like this in the android source code. – Jap Mul Jun 24 '12 at 19:23
  • @jagsler I am trying to achieve something similar, have you noticed a problem where while scrolling the view layouts get changed somehow? – kabuto178 Feb 25 '14 at 20:59
  • @kabuto178 I had that same problem when I didn't override the getViewTypeCount() method. – William Kenney Mar 05 '14 at 20:28
  • @WilliamKenney actually that did fix it, but all this time I thought that would have not much effect, it seems the recycling of views have something to do with it – kabuto178 Mar 05 '14 at 20:33
  • Finally an example of using multiple views in a cursor adapter. To me, key here was implementing 'getItemViewType' – miroslavign Aug 23 '16 at 21:42
  • You saved my nights! :) Thx – Priyesh Kumar Oct 13 '16 at 20:26
  • Without overriding `getItemViewType` and `getViewTypeCount` also my adapter is working as expected. So whats the use of them. i am not able to figure it out. – kanudo Jul 16 '17 at 05:09
2

Take a look to this example, you can easily adapt it for solving your problem. It's pretty straightforward.

gwvatieri
  • 5,133
  • 1
  • 29
  • 29
  • Thanks for the example. I think i understand (most part of) the code given in the example but I get confused at the point where I don't have a getView method but a newView and bindView method.. how can I implement the code given in the example in my case? – Jap Mul Dec 12 '11 at 20:52
  • 1
    CursorAdapter has an implementation of getView() that delegates to newView() and bindView(), in such a way as enforces the row recycling pattern. So in newView(), you would create the ViewHolder for the row and associate it with setTag(). In bindView(), you would retrieve the ViewHolder via getTag(); at the end you just need to adapt/split the same logic between the 2 methods. Busy now, but I can write some code tonight in case you need... – gwvatieri Dec 12 '11 at 21:14
  • Thanks for the info! I'm going to try it myself first but I'll let you know if don't get it to work. – Jap Mul Dec 12 '11 at 21:16
  • Gonna write some code tonight and I'll get back to you. Let me know if you make it work... – gwvatieri Dec 12 '11 at 22:16
  • Still can't get it to work. Can you please help me out with the code? – Jap Mul Dec 13 '11 at 19:31
  • Hey jagsler, I started but did not finish yet, pretty busy at work. I'll try to finish it... – gwvatieri Dec 13 '11 at 23:34
  • I updated the code I got working for now. Still don't know how to make it work depending on some data in the cursor.. – Jap Mul Dec 20 '11 at 11:17
0

Another possible solution regarding the access to the cursor in the getItemViewType method is the following:

@Override
public int getChildType(int groupPosition, int childPosition) {
    Cursor c = getChild(groupPosition, childPosition);
    if(c.getString(c.getColumnIndex(Contract.MyColumn)).equals("value"))
        return 0;
    else return 1;
}
Nick
  • 966
  • 1
  • 10
  • 20