K. D.
K. D.

Reputation: 4219

ListView entries are changing their layout when scrolling

Hi I found a very strange problem that I can't understand.. hopefully someone can help me:

My list looks great if all views have place on the screen. As soon as the screen is smaller (or the list is longer) sometimes entries have different views than they should have. This problem can be constrained by scrolling up or down so that entries get out of the window.

I have a listview with different entry-types in it that have different layout files. This is the method that should decide what layout will be shown:

public View getView(int position, View view, ViewGroup parent) {
        NavigationListEntry i = entries.get(position);
        View v = view;
        if (v == null)
            switch(i.Type) {
            case ACTIVE_ENTRY:
                v = inflater.inflate(R.layout.list_nav_row_active, null);
                break;
            case HEADER:
                v = inflater.inflate(R.layout.list_nav_row_header, null);
                break;
            ...
            default:
                v = inflater.inflate(R.layout.list_nav_row_active, null);
                break;
            }
}

Do you have any ideas why this could occur?

/edit It seems to work if I just remove "if (v == null)"

Upvotes: 0

Views: 136

Answers (3)

Abhishek Nandi
Abhishek Nandi

Reputation: 4275

If you remove if(v==null) you are not reusing the views which have already been inflated. If you do that the list view will be a bit sluggish.

The best way to do is

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    NavigationListEntry i = getItem(position);
    if(null == convertView){
        convertView = inflateNewView(i.type);
        holder = (ViewHolder) convertView.getTag();
    } else{
        //getting tag to obtain the already found views
        holder = (ViewHolder) convertView.getTag();
        if(holder.type != i.type){
            convertView = inflateNewView(i.type); 
            holder = (ViewHolder) convertView.getTag();
        }
    }

    //always update the elements 
    holder.title.setText(i.getTitle());
    holder.desc.setText(i.getDesc());
    holder.content.setText(i.getContent());

    return convertView;
}

/**
 * Inflates a new view for the specified type
 * @return the newly inflated view
 */
private View inflateNewView(int type){
        View convertView = null;
        switch(type) {
        case ACTIVE_ENTRY:
            convertView = inflater.inflate(R.layout.list_nav_row_active, null);
            break;
        case HEADER:
            convertView = inflater.inflate(R.layout.list_nav_row_header, null);
            break;
        ...
        default:
            convertView = inflater.inflate(R.layout.list_nav_row_active, null);
            break;
        }
        holder = new ViewHolder();
        convertView = inflater.inflate(LAYOUT_RESOURCE, null);
        holder.title = (TextView) convertView.findViewById(R.id.txtTitle);
        holder.desc = (TextView) convertView.findViewById(R.id.txtDesc);
        holder.content = (TextView) convertView.findViewById(R.id.txtContent);
        holder.type = type;
        //setting tag to reduce hierarchy lookup
        convertView.setTag(holder);

    return convertView;
}
/**
 * Holder class to improve performance. Helps in reducing view hierarchy lookup
 */
private static class ViewHolder {

    TextView title;
    TextView desc;
    TextView content;
    int type;

}   

This is the best way which will atleast attempt to recycle your views. Hope this helps

Upvotes: 1

apenga
apenga

Reputation: 37

Maybe the position will changing while scrolling or updating view. Suggest using an array instead of position

Upvotes: -1

s.d
s.d

Reputation: 29436

You have a problem here, the recycled View you get in parameter might not be of the same Type you want to return. Let's say v is of type A, and its not null, the code you posted says nothing about that.

Upvotes: 1

Related Questions