Android listview using ViewHolder
Asked Answered
G

5

8

I have a problem. I'm attempting to change an icon in my listview after it has been clicked. It works correctly although are not modified only the clicked icons but also those who are not displayed. For example if I click the icon in the first item of the listview, also the fifth icon changes. This behaviour is repeated for all the following items (every five items of the listview). This is my getView method:

   public class AlphabeticalAdapter extends ArrayAdapter<String>
   {
       int layoutResourceId; 
       private final Context context;
       private List<String> data;
       private ProgressDialog mProgressDialog;
       private ImageView downloadImageButton;


       public AlphabeticalAdapter(Context context, int resource, List<String> data){
           super(context, resource, data);
           this.layoutResourceId = resource;
           this.context = context;
           this.data = data;    
       }

       public View getView(int position, View convertView, ViewGroup parent) {

          // View rowView = convertView;
           final ViewHolder viewHolder;

           if (convertView == null) {

               LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);


               convertView  = inflater.inflate(R.layout.catalogslist_single_row, parent, false);

           viewHolder = new ViewHolder();

           viewHolder.catlogTitle=(TextView)convertView.findViewById(R.id.txtTitle);
           viewHolder.icon=(ImageView)convertView.findViewById(R.id.imageView2); 
           viewHolder.downloadImageButton=(ImageView)convertView.findViewById(R.id.downloadImageButton);

           //downloadImageButton = (ImageView)rowView.findViewById(R.id.downloadImageButton);

           viewHolder.position = position;


           viewHolder.downloadImageButton.setOnClickListener(new OnClickListener() {
               @Override  
               public void onClick(View v) {
                     System.out.println("DOWNLOAD PRESSED");

                     viewHolder.downloadImageButton = (ImageView)v.findViewById(R.id.downloadImageButton);
                     viewHolder.downloadImageButton.setImageResource(R.drawable.icon_ok);
                     viewHolder.downloadImageButton.setTag("downloaded");
                     //rowView.setTag("downloaded");


                 }
             });



           convertView.setTag(viewHolder);

           }

           else{
               viewHolder= (ViewHolder)convertView.getTag(); 
           }

           viewHolder.catlogTitle.setText(data.get(position));
           viewHolder.catlogTitle.setTypeface(regularDin);
           viewHolder.icon.setImageResource(R.drawable.cata);


           if(viewHolder.downloadImageButton.getTag() == "downloaded"){
             downloadImageButton = (ImageView)convertView.findViewById(R.id.downloadImageButton);
             downloadImageButton.setImageResource(R.drawable.icon_ok);
           }
           else{
               downloadImageButton = (ImageView)convertView.findViewById(R.id.downloadImageButton);
                 downloadImageButton.setImageResource(R.drawable.icon_download);
           }


           viewHolder.position = position;

        return convertView;

       } //close getView 

...

And this is my ViewHolder class:

      static class ViewHolder{
       ImageView downloadImageButton;
       TextView catlogTitle;
       ImageView icon;
       int position;
   }
Globulin answered 21/7, 2014 at 12:31 Comment(0)
N
10

Change your code at below. I think you're missing that.

public class AlphabeticalAdapter extends ArrayAdapter<String> {
    int layoutResourceId;
    private final Context context;
    private List<String> data;
    private List<String> tags;
    private ProgressDialog mProgressDialog;
    private ImageView downloadImageButton;

    public AlphabeticalAdapter(Context context, int resource, List<String> data) {
        super(context, resource, data);
        this.layoutResourceId = resource;
        this.context = context;
        this.data = data;
        tags = new ArrayList<String>();
        int size = data.size();
        for (int i = 0; i < size; i++) {
            tags.add("tag");
        }
    }

    static class ViewHolder {
        ImageView downloadImageButton;
        TextView catlogTitle;
        ImageView icon;
        int position;
    }

    public View getView(final int position, View convertView, ViewGroup parent) {

        // View rowView = convertView;
        final ViewHolder viewHolder;

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            // convertView = inflater.inflate(R.layout.catalogslist_single_row,
            // parent, false);
            viewHolder = new ViewHolder();
            viewHolder.position = position;
            viewHolder.downloadImageButton
                    .setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            System.out.println("DOWNLOAD PRESSED");
                            viewHolder.downloadImageButton.setTag("downloaded");
                            tags.add(position, "downloaded");
                        }
                    });
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        viewHolder.catlogTitle.setText(data.get(position));
        viewHolder.catlogTitle.setTypeface(regularDin);
        viewHolder.icon.setImageResource(R.drawable.cata);

        if (tags.get(position) == "downloaded") {
            downloadImageButton.setImageResource(R.drawable.icon_ok);
        } else {
            downloadImageButton.setImageResource(R.drawable.icon_download);
        }

        viewHolder.position = position;
        return convertView;
    } // close getView
}
Nullifidian answered 21/7, 2014 at 12:41 Comment(7)
@Globulin i edited my code, see this and tell its help youNullifidian
This is wrong. Read my answer to understand why. There number of ViewHolder objects not equals the number of the rows. What would be the meaning of the ViewHolder pattern otherwise?Tirrell
@Tirrell yes you are right. Other different list one added then its workNullifidian
@Tirrell could you paste an example please?Globulin
@Globulin i updated code its work i think. You can also use array list to hashmap or TreeSet for selected position.Nullifidian
@Globulin Officially not:) You have to write it to understand it.Tirrell
@DivyangMetalia Yeah now it should work. But there is a low chance that Mark understood what is the problem by copying your code:)Tirrell
T
5

There are as many convertViews as many row visible in the same time in your ListView (the system reuses it). So you actually have 5 convertView, and because of that you have 5 ImageView for the icons. The problem is that you use those ImageView's tag to store the "downloaded" information. That is 5 state, and that is why you see every fifth row downloaded while you scroll in the list.

I guess now you see that it won't work. You need to store the downloaded state for every item, so you have to change the underlying List<String> to List<ListItem>, where ListItem can store the downloaded state for the actual row.

After that, all you have to do is to update the convertView's ImageView (in getView()) to show the correct icon.

Tirrell answered 21/7, 2014 at 12:42 Comment(0)
A
1

Change your code like this. Add null check with convertView before your try block.

    final MenuItem   menuItem = getItem(position);
    View view = convertView;
    final ViewHolder viewHolder;

if (convertView == null) {

    LayoutInflater inflater;

        inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.menu_item, parent, false);
        viewHolder = new ViewHolder();
//      viewHolder.half = (TextView) view.findViewById(R.id.half);
        viewHolder.name = (TextView) view.findViewById(R.id.name);
        viewHolder.description = (TextView) view.findViewById(R.id.description);
        viewHolder.price = (TextView) view.findViewById(R.id.price);
        viewHolder.add = (Button) view.findViewById(R.id.add);
        viewHolder.selectedView = view.findViewById(R.id.selectedView);
        viewHolder.remove = (Button) view.findViewById(R.id.remove);
        viewHolder.total = (TextView) view.findViewById(R.id.itemTotal);
        viewHolder.quantity = (TextView) view.findViewById(R.id.quantity);
        view.setTag(viewHolder);
}else{
    viewHolder= (ViewHolder)convertView.getTag(); 
}
Aggress answered 5/2, 2016 at 9:20 Comment(0)
C
1

You can try this

public class CustomArrayAdapter extends ArrayAdapter {

// declare your custom list with type;
private List<YourModelClass> allData = new ArrayList<YourModelClass>();

public CustomArrayAdapter(@NonNull Context context, List<YourModelClass> allData) {
    super(context, R.layout.your_layout, allData); // add your_layout.xml
    this.allData = allData;
}

class ViewHolder {
    TextView name, phone; // declare your your_layout.xml view type
}

@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    ViewHolder holder = new ViewHolder();
    if (convertView == null) {

        convertView = inflater.inflate(R.layout.your_layout, parent, false); // inflate your_layout.xml

        //initialize your your_layout.xml view
        holder.name = convertView.findViewById(R.id.tv_item_name);
        holder.phone = convertView.findViewById(R.id.tv_item_phone);

        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    //set value into your_layout.xml
    holder.name.setText(allData.get(position).getName());
    holder.phone.setText(allData.get(position).getNumber());

    return convertView;
}

}

Cramp answered 21/9, 2018 at 21:47 Comment(0)
C
0
public class AndroidListViewActivity extends ListActivity 
{
   private ListView listView;
   private String names[] = {
        "HV CAPACITOR",
        "LV CAPACITORCSS",

         };

private String desc[] = {
        "The Powerful Hypter Text Markup Language 5",
        "Cascading Style Sheets",

};


private Integer imageid[] = {
        R.drawable.hv_capacitor,
        R.drawable.lv_capacitor,

};

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
   // setContentView(R.layout.capacitor_layout);
    // storing string resources into Array
    String[] product_name = getResources().getStringArray(R.array.product_name);
    // Binding Array to ListAdapter
    this.setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, R.id.label, product_name));

    ListView lv = getListView();

    // listening to single list item on click

    lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view,
                                int position, long id) {

            // selected item
            String product = ((TextView) view).getText().toString();

            // Launching new Activity on selecting single List Item
            Intent i = new Intent(getApplicationContext(), SingleListItem.class);
            // sending data to new activity
            i.putExtra("product", product);
            startActivity(i);

        }
    });


    CapacitorList capacitorList = new CapacitorList(this, names, desc, imageid);
    listView = (ListView) findViewById(R.id.listView);
    listView.setAdapter(capacitorList);

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

        // Launching new Activity on selecting single List Item
        Intent i = new Intent(getApplicationContext(), CapacitorList.class);
        // sending data to new activity

       // startActivity(i);

        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            Toast.makeText(getApplicationContext(), "You Clicked " + names[i], Toast.LENGTH_SHORT).show();
        }
    });

}

    @Override
    public boolean onCreateOptionsMenu (Menu menu){
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected (MenuItem item){
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);


    }
}
Corbel answered 10/3, 2016 at 10:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.