0

In my project I have a listView with star image. If a user touches a star item add to favorite. All code is correct but when listview scroll star image change to unfavorite. This is my code:

 private class MyAdapter extends ArrayAdapter<String> {

    public MyAdapter(Context context, int resource, int textViewResourceId,
                     String[] strings) {
        super(context, resource, textViewResourceId, strings);
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View row = inflater.inflate(R.layout.custom_list_item, parent, false);

        String my_string = title[position].toString();
        final TextView content_title = (TextView) row.findViewById(R.id.contentitle);
        final ImageView favicon = (ImageView) row.findViewById(R.id.favicon);
        content_title.setText(my_string);
        content_title.setTypeface(koodakfont);

        if (favicon.getTag().equals("fav")) {
            favicon.setImageResource(R.drawable.favicon);
            favicon.setTag("fav");
        }

        favicon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (favicon.getTag().equals("unfav")) {
                    favicon.setImageResource(R.drawable.favicon);
                    favicon.setTag("fav");
                } else {
                   favicon.setImageResource(R.drawable.unfavicon);
                    favicon.setTag("unfav");
                }
            }
        });

        return row;
    }

EDIT : the below edit doesn't really work for me either.

static class ViewHolder {
    ImageView favicon;
}


private class MyAdapter extends ArrayAdapter<String> {


    public MyAdapter(Context context, int resource, int textViewResourceId,
                     String[] strings) {
        super(context, resource, textViewResourceId, strings);
    }



    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View row = inflater.inflate(R.layout.custom_list_item, parent, false);

        String my_string = title[position].toString();
        final TextView content_title = (TextView) row.findViewById(R.id.contentitle);
        final ViewHolder holder = new ViewHolder();
        holder.favicon = (ImageView) row.findViewById(R.id.favicon);
        content_title.setText(my_string);
        content_title.setTypeface(koodakfont);

        if (holder.favicon.getTag().equals("fav")) {
            holder.favicon.setImageResource(R.drawable.favicon);
            holder.favicon.setTag("fav");
        }

        holder.favicon.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                if (holder.favicon.getTag().equals("unfav")) {
                    holder.favicon.setImageResource(R.drawable.favicon);
                    holder.favicon.setTag("fav");
                } else {
                    holder.favicon.setImageResource(R.drawable.unfavicon);
                    holder.favicon.setTag("unfav");
                }


            }
        });

        return row;
    }
2Dee
  • 8,609
  • 7
  • 42
  • 53
bnnoor
  • 656
  • 2
  • 13
  • 31

3 Answers3

4

It's a problem of View recycling, basically when you scroll, the View is created again, so the state of your star icon is lost. You would need to implement a logic to check in which state you need to set the icon for every call to getView. A good starting point could be to use the position of the item in the ListView to check, when the View is created, if you need your favorite icon to be set to starred or unstarred. I recommend you read this answer, which explains the mechanism in detail. Here's a simplified example of what you could do :

private boolean[] favorites; // initialize this array on creation of your adapter with the same size as your listView

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    //the rest of your code 

    if(favorites[position]){
        holder.favicon.setImageResource(R.drawable.favicon);
    else{
        holder.favicon.setImageResource(R.drawable.unfavicon);
    }
    holder.favicon.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            if (favorites[position]) {
                holder.favicon.setImageResource(R.drawable.unfavicon);
                favorites[position] = false;
            } else {
                holder.favicon.setImageResource(R.drawable.favicon);
                favorites[position] = true;
            }
        }
    });

I also recommend you start using the ViewHolder pattern for efficiency reasons, although you problem is not related to that.

Community
  • 1
  • 1
2Dee
  • 8,609
  • 7
  • 42
  • 53
  • question update . i know your answer is correct but i cant find correct position . can you edit my code? – bnnoor Dec 01 '15 at 16:05
  • Only you can know what kind of logic you need to implement, it depends on wether the choice of the user needs to be persisted between app launches and what kind of data you wish to persist. I provided a simple example of what you need to do, but I recommend you take your time to read about the mechanisms yourself, you didn't implement the ViewHolder properly in your updated code. Spend the time to learn ListView in details, it's worth the investment and more importantly, there's no way around it if you want to develop further ;) – 2Dee Dec 01 '15 at 16:21
1

Here your problem is favicon object is created again when you scroll ListView. in which tag is not set, as you are setting it programmatically.

My suggestion is use View-Holder pattern.

Dhaval Patel
  • 10,119
  • 5
  • 43
  • 46
0

First of all, you're inflating a new view each time the getView is called when they should be reused. Check the view holder pattern - Smooth Scrolling

Now about your issue, you either need an array to save the favs state values for each position (an array with the same size as titles) or set the list mode to CHOICE_MODE_MULTIPLE and change the favion state with a backgoung selector.