Mr. Kro
Mr. Kro

Reputation: 138

Make first ListView item appear in a different layout

I'm trying to make a ListView with the first item displayed in a different layout, and others in a common layout. Both layouts have the same elements which in pairs have the same names. When I do like this:

public View getView(int position, View convertView, ViewGroup parent) {        
    if(convertView == null) {
        if(position == 0){
            convertView = inflater.inflate(R.layout.article_list_top_item, parent, false);
            Log.d("ALA", "pos = " + position + ", inflated top");
        }
        else {
            convertView = inflater.inflate(R.layout.article_list_item, parent, false);
            Log.d("ALA", "pos = " + position + ", inflated normal");
        }
    }
    // setText, setBitmap etc here
    return convertView;
}

it didn't work. From the log I could say, inflater.inflate was triggered 6 times, inflated top 1 time and inflated normal 5 times.

What displayed is, article[0] was in layout article_list_top_item and article[1] ~ article[5] was in article_list_item.

Up until here it's ok, but the pattern repeated, which means article[6], article[12], [18],... were all in the layout article_list_top_item which is not what I want.

What can I do to make ONLY the first article to appear in article_list_top_item??

P.S. I tried renaming elements in article_list_top_item.xml and if-branched the setText setImage process, didn't help.

I tried adding else return convertView; before //setText lines, it became a mess.

I thought of making a dedicated layout element for the first item only, but that's not what I want because the whole list lays under a SwipeRefreshLayout

Please help.

Upvotes: 4

Views: 2135

Answers (3)

sonic
sonic

Reputation: 1904

You should use different itew view type. Your adapter reuse the view already inflated, so if you want to different kind you should tell him :

Create a holder for each of your view type

private class FirstHolder {
    //add a field for each subview in view type 1
}
private class SecondHolder {
    //add a field for each subview in view type 2
}

Override the getViewTypeCount() method

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

Override the getItemViewType(int position) method. This method tells which type of view is used for each position.

@Override
public int getItemViewType(int position) {
    if (position == 0) {
        return 0;
    } else {
        return 1;
    }
}

Build and setup the view :

public View getView(int position, View convertView, ViewGroup parent) {
    if (position == 0) {
        FirstHolder holder;
        if (convertView == null) {
            holder = new FirstHolder();
            convertView = inflater.inflate(R.layout.whatever_firstlayout, parent, false);
            //for each field of holder find the subview
            convertView.setTag(holder);
        } else {
            holder = (FirstHolder) convertView.getTag();
        }
        //set the data in subview with holder fields
    } else {
        SecondHolder holder;
        if (convertView == null) {
            holder = new SecondHolder();
            convertView = inflater.inflate(R.layout.whatever_secondlayout, parent, false);
            //for each field of holder find the subview
            convertView.setTag(holder);
        } else {
            holder = (SecondHolder) convertView.getTag();
        }
        //set the data in subview with holder fields
    }
    return convertView;
}

Upvotes: 6

Mr. Kro
Mr. Kro

Reputation: 138

I found the problem. Exactly like @sonic said, I want to use different kinds of views for the same ListView so I have to tell him so, by overriding getViewTypeCount() and getItemViewType(int position). Working code:

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

@Override
public int getItemViewType(int pos){
    return pos > 0 ? 1 : 0;
}

public View getView(int position, View listItem, ViewGroup parent) {
    if(listItem == null) 
        listItem = inflater.inflate(getItemViewType(position) == 0 ?
                   R.layout.article_list_top_item : R.layout.article_list_item
                   , parent, false);
    // setText setBitmap etc. here
}

Comments: It works even if I don't use getViewTypeCount() and getItemViewType(int position) anywhere, but overriding them matters. Doubting getItemViewType(int position) would do anything, I tried not overriding it - and the result is, I had to override both to make it work.

I wonder how. Maybe everytime the view is inflated with a layout that's never used before, then the system assign that layout with a number from 0 to getViewTypeCount() - 1? Otherwise, where have it been used (in parent classes' code) to make it matter?

I'll leave this here to think later.

Upvotes: 0

Selim YILDIZ
Selim YILDIZ

Reputation: 378

You can use addHeaderView. For example;

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View head = inflater.inflate(R.layout.headerlayout, listview, false);
listview.addHeaderView(head);

Upvotes: 1

Related Questions