Omar Sherif Mansour
Omar Sherif Mansour

Reputation: 63

Expandable List View Duplicate Views

Simply my issue goes as the following.
I am implementing an ExapndableListView, the first group has children to have a layout consisting of those 3 : TextView, ImageView, ImageView.
now, when a child is clicked i set the visibility of one of the two imageviews using v.findViewById().setVisibility(), and its working good as i imagined.
The problem is when the list has more than 10 children, the android system recycles the view using the last hidden one at the top when scrolling down, now when i click the child of position "0", i toggle the image of THAT view only while the others are not changed, good so far, but when i scroll down and the android system recycles the view using the child "0" view in the child of position "11", it changes the textView corresponding to child "11" as it should but the view used for child "11" is the view of child "0" thus the same image that was toggled earlier it appears on the view of child "11" as if it was clicked as well but it wasn't ! im doing this :

@Override
    public View getChildView(final int parentPosition, final int childPosition,  boolean isLastChild, View convertView, ViewGroup parent) {

    Log.d("status","parent : "+parentPosition + " child : " + childPosition + " View : "+convertView + " ViewGroup : "+parent);
    int itemType = 25;
    itemType = getChildType(parentPosition, childPosition);
    String child_title = (String) getChild(parentPosition,childPosition);
    if (convertView == null)
    {
        if (itemType == 0)
        {
            LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.activities2_child_layout, parent, false);

        } else if (itemType == 1) {
            LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.activities2_child2_layout, parent, false);
        } else if (itemType == 2) {
            LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.activities2_child2_layout, parent, false);
        }
    }
    if (itemType == 0)
    //region parent 0 child handling
    {
        Log.d("Child", childPosition + " : " + child_title);

        final TextView child_textview = (TextView) convertView.findViewById(R.id.activities2_child_txt);
        final ImageView img_Likes = (ImageView) convertView.findViewById(R.id.activities2_img_like);
        final ImageView img_Dislikes = (ImageView) convertView.findViewById(R.id.activities2_img_dislike);
        child_textview.setText(child_title);

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

                switch (AAChildClicks[childPosition]) {
                    case 0:
                        AAChildClicks[childPosition]++;
                        img_Likes.setVisibility(View.VISIBLE);
                        //add to total
                        All_Likes.add(child_textview.getText().toString());
                        Log.d("Likes", "Likes + " + child_textview.getText().toString());
                        break;
                    case 1:
                        AAChildClicks[childPosition]++;
                        img_Likes.setVisibility(View.GONE);
                        img_Dislikes.setVisibility(View.VISIBLE);
                        String child = child_textview.getText().toString();
                        //remove from total
                        All_Likes.remove(child_textview.getText().toString());
                        Log.d("Likes", "Likes - " + child_textview.getText().toString());
                        //add to total
                        All_Dislikes.add(child_textview.getText().toString());
                        Log.d("Likes", "Dislikes + " + child_textview.getText().toString());
                        break;
                    case 2:
                        AAChildClicks[childPosition] = 0;
                        img_Likes.setVisibility(View.GONE);
                        img_Dislikes.setVisibility(View.GONE);
                        String child2 = child_textview.getText().toString();
                        //remove from total
                        All_Dislikes.remove(child_textview.getText().toString());
                        Log.d("Likes", "Dislikes - " + child_textview.getText().toString());
                        break;
                }
            }

        });
    }
    //endregion

    if (itemType == 1)
    //region parent 1 child handling
    {
        TextView child_textview = (TextView) convertView.findViewById(R.id.activities2_child2_txt);
        child_textview.setText(child_title);
    }
    //endregion

    if (itemType == 2)
    //region parent 2 child handling
    {
        TextView child_textview = (TextView) convertView.findViewById(R.id.activities2_child2_txt);
        child_textview.setText(child_title);
    }
    //endregion

    return convertView;
}

How to avoid such duplication/error ?!

Upvotes: 2

Views: 916

Answers (2)

NameSpace
NameSpace

Reputation: 10177

When a view gets recycled, its components will keep the same visibility state they had previously. So if you hid parts of the View, those will be hidden when it gets recycled.

Thus, you need to do two things:

  1. Set the View's visibility to the proper state every call of GetChildView.

  2. You need to keep track of position-data outside of the views. Right now your only record of a views visibility is on the view itself. When that view gets recycled, your record is lost (the view's state becomes the starting state of some other position -- which is why we have to overwrite it in #1).

You should be keeping track of view visibility in some sort of List or Node type architecture -- you can't store that data on the views, since they are not permanently associated with any one position.

Upvotes: 1

k3b
k3b

Reputation: 14755

Currently you store the state in the itemView img_Likes.setVisibility(View.VISIBLE);

you have to store it in your modell, too

  ((MyType) getChild(parentPosition,childPosition)).setIsVisible(true)

If you (re)create the listview item you use that info to (en/dis)able visibility

 img_Likes.setVisibility((((MyType) getChild(parentPosition,childPosition)).getIsVisible()) ? View.VISIBLE : View.GONE);

Upvotes: 1

Related Questions