ListView loses state of rows during scroll

1

I have a ListView and I use the following layout for the adapter:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llContainer"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="5dp"
    android:layout_marginTop="5dp"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tvLocal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="question"
        android:textColor="@color/app_gray"
        android:textSize="12sp" >
    </TextView>

    <TextView
        android:id="@+id/tvQuestion"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="question"
        android:textColor="@color/app_gray"
        android:textSize="12sp"
        android:textStyle="bold" >
    </TextView>

    <LinearLayout
        android:id="@+id/llContainerLikeDislike"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp"
        android:orientation="vertical"
        android:visibility="gone" >

        <TextView
            android:id="@+id/tvAnswer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:textColor="@color/app_blue"
            android:textSize="12sp" />

        <LinearLayout
            android:id="@+id/llContainerButtons"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="5dp"
            android:orientation="horizontal" >

            <LinearLayout
                android:id="@+id/llLike"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:padding="5dp"
                android:clickable="true"
                android:gravity="center_horizontal"
                android:orientation="vertical" >

                <ImageView
                    android:id="@+id/ivLike"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:contentDescription="@null"
                    android:layout_margin="5dp"
                    android:src="@drawable/background_btn_like" />

                <TextView
                    android:id="@+id/tvHelped"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Helped"
                    android:textColor="@color/app_gray"
                    android:textSize="12sp" >
                </TextView>

                <TextView
                    android:id="@+id/tvNumLike"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="@color/app_gray"
                    android:textSize="12sp" >
                </TextView>
            </LinearLayout>

            <LinearLayout
                android:id="@+id/llDisLike"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:padding="5dp"
                android:clickable="true"
                android:gravity="center_horizontal"
                android:orientation="vertical" >

                <ImageView
                    android:id="@+id/ivDisLike"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:contentDescription="@null"
                    android:layout_margin="5dp"
                    android:src="@drawable/background_btn_dislike" />

                <TextView
                    android:id="@+id/tvNotHelp"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Not Help"
                    android:textColor="@color/app_gray"
                    android:textSize="12sp" >
                </TextView>

                <TextView
                    android:id="@+id/tvNumDisLike"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="@color/app_gray"
                    android:textSize="12sp" >
                </TextView>
            </LinearLayout>

        </LinearLayout>

    </LinearLayout>

</LinearLayout>

QA class:

public class QA {

    private int id;
    private String question, answer, answer_at, state, city, name;
    public enum state { like, dislike };
    private long up_votes_count, down_votes_count;
    private boolean visible, like, wasVoted;

    // get and setters

}

In case llContainer ( LinearLayout ) should receive a click event and display the LinearLayout llContainerLikeDislike, as an expandable list. Control whether llContainerLikeDislike is with its Visibility Gone passed to Visible and vice versa. I use this method for this:

public static void expand(final View v, final ListView lv, final int position) {
    v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    final int targetHeight = v.getMeasuredHeight();

    v.getLayoutParams().height = 0;
    v.setVisibility(View.VISIBLE);
    Animation a = new Animation()
    {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            v.getLayoutParams().height = interpolatedTime == 1
                    ? LayoutParams.WRAP_CONTENT
                    : (int)(targetHeight * interpolatedTime);
            v.requestLayout();

            //Moves the listview scroll so that the expanding area is visible.
            lv.setSelectionFromTop(position, v.getLayoutParams().height);
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };

    // 1dp/ms
    a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));
    v.startAnimation(a);
}

public static void collapse(final View v) {
    final int initialHeight = v.getMeasuredHeight();

    Animation a = new Animation()
    {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            if(interpolatedTime == 1){
                v.setVisibility(View.GONE);
            }else{
                v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
                v.requestLayout();
            }
        }

        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };

    // 1dp/ms
    a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
    v.startAnimation(a);
}

No Adapter use ViewHolder to control the reference of each line with setTag() and getTag() . In case each line is correctly maintaining the data of the object qa during the scroll. However the scroll is changing the behavior of the lines that control the expansion and retraction of the lines and, enabling and disabling a line that had its ImageView selected. I use ImageView 's as if it were buttons to give a like or dislike in a row, when clicked it is disabled and it changes the appearance. In short, the data in each row is correct for the objects qa but that of the components such as Visibility Gone/Visible line, color change, enable and disable during ListView scroll are misbehaving. If a line for example of position 0 is Visible , disabled, and has changed color, moving the scroll of ListView a random line below has the same status as line 0. I used the debug and the methods are getting the reference correctly and, being called only once, there is no repetition for the random lines.

Follow getView() of adapter:

public class QAAdapter extends ArrayAdapter<QA> implements Filterable {

    private List<QA>filteredData;

    private ArrayList<QA> arrayQA;
    private ViewHolder holder;
    private final LayoutInflater inflater;
    private Activity activity;

    public QAAdapter(Activity activity,
            ArrayList<QA> arrayQA) {
        super(activity, 0);

        this.inflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.arrayQA = arrayQA;
        this.filteredData = arrayQA; 
        this.activity = activity;
    }

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

    holder = new ViewHolder();

    if (convertView == null) {
        convertView = inflater.inflate(R.layout.item_pergunta, parent,
                false);

        Typeface tfLight = Typeface.createFromAsset(activity.getAssets(),
                "fonts/Oswald-Light.ttf");

        Typeface tfBold = Typeface.createFromAsset(activity.getAssets(),
                "fonts/Oswald-Bold.ttf");

        holder.tvAjudou = (TextView) convertView
                .findViewById(R.id.tvAjudou);
        holder.tvNaoAjudou = (TextView) convertView
                .findViewById(R.id.tvNaoAjudou);

        holder.tvLocal = (TextView) convertView.findViewById(R.id.tvLocal);
        holder.tvLocal.setTypeface(tfLight);

        holder.tvQuestion = (TextView) convertView
                .findViewById(R.id.tvQuestion);
        holder.tvQuestion.setTypeface(tfBold);

        holder.tvAnswer = (TextView) convertView
                .findViewById(R.id.tvAnswer);
        holder.tvAnswer.setTypeface(tfLight);

        holder.tvNumLike = (TextView) convertView
                .findViewById(R.id.tvNumLike);
        holder.tvNumLike.setTypeface(tfLight);

        holder.tvNumDisLike = (TextView) convertView
                .findViewById(R.id.tvNumDisLike);
        holder.tvNumDisLike.setTypeface(tfLight);

        holder.ivLike = (ImageView) convertView.findViewById(R.id.ivLike);

        holder.ivDisLike = (ImageView) convertView
                .findViewById(R.id.ivDisLike);

        holder.llContainerButtons = (LinearLayout) convertView
                .findViewById(R.id.llContainerButtons);

        holder.llContainer = (LinearLayout) convertView
                .findViewById(R.id.llContainer);

        holder.llContainerLikeDislike = (LinearLayout) convertView
                .findViewById(R.id.llContainerLikeDislike);
        holder.llContainerLikeDislike.setVisibility(View.GONE);

        holder.llLike = (LinearLayout) convertView
                .findViewById(R.id.llLike);

        holder.llDisLike = (LinearLayout) convertView
                .findViewById(R.id.llDisLike);

        holder.llContainer.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                final int position2 = ((ListView) parent)
                        .getPositionForView(v);

                QA qa = getItemQa(position2);

                boolean visibility = qa.isVisible();

                if (!visibility) {

                    qa.setVisible(true);

                    UtilsLab.expand(
                            v.findViewById(R.id.llContainerLikeDislike),
                            ((ListView) parent), position2);
                } else {
                    qa.setVisible(false);

                    UtilsLab.collapse(v
                            .findViewById(R.id.llContainerLikeDislike));
                }

                QASelected selectQASelectedById = QASelectedModel
                        .selectQASelectedById(activity, qa.getId());

                if (selectQASelectedById != null) {
                    v.findViewById(R.id.llLike).setEnabled(false);
                    v.findViewById(R.id.llDisLike).setEnabled(false);

                    boolean isLike = selectQASelectedById.isLike();

                    isLike = qa.isLike();
                    qa.setWasVoted(true);

                    v.findViewById(R.id.llLike).setSelected(isLike);
                    v.findViewById(R.id.llDisLike).setSelected(!isLike);

                    ImageView ivLike = (ImageView) v
                            .findViewById(R.id.ivLike);
                    ivLike.setSelected(isLike);

                    ImageView ivDisLike = (ImageView) v
                            .findViewById(R.id.ivDisLike);
                    ivDisLike.setSelected(!isLike);

                    if (isLike) {
                        ((TextView) v.findViewById(R.id.tvAjudou))
                                .setTextColor(activity.getResources()
                                        .getColor(R.color.app_azul_claro));

                        ((TextView) v.findViewById(R.id.tvNumLike))
                                .setTextColor(activity.getResources()
                                        .getColor(R.color.app_azul_claro));

                        ((TextView) v.findViewById(R.id.tvNaoAjudou))
                                .setTextColor(activity.getResources()
                                        .getColor(R.color.app_cinza_claro));

                        ((TextView) v.findViewById(R.id.tvNumDisLike))
                                .setTextColor(activity.getResources()
                                        .getColor(R.color.app_cinza_claro));
                    } else {
                        ((TextView) v.findViewById(R.id.tvAjudou))
                                .setTextColor(activity.getResources()
                                        .getColor(R.color.app_cinza_claro));

                        ((TextView) v.findViewById(R.id.tvNumLike))
                                .setTextColor(activity.getResources()
                                        .getColor(R.color.app_cinza_claro));

                        ((TextView) v.findViewById(R.id.tvNaoAjudou))
                                .setTextColor(activity.getResources()
                                        .getColor(R.color.app_vermelho));

                        ((TextView) v.findViewById(R.id.tvNumDisLike))
                                .setTextColor(activity.getResources()
                                        .getColor(R.color.app_vermelho));
                    }
                }

                notifyDataSetChanged();
            }
        });

        holder.llLike.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                QA qa = getItemQa(position);

                int value = (int) (qa.getUp_count() + 1);
                qa.setUp_count(value);

                qa.setLike(true);
                qa.setWasVoted(true);

                ((LinearLayout) v).setEnabled(false);
                ((LinearLayout) ((LinearLayout) v.getParent())
                        .findViewById(R.id.llDisLike)).setEnabled(false);
                ((ImageView) v.findViewById(R.id.ivLike)).setSelected(true);
                ((TextView) v.findViewById(R.id.tvAjudou))
                        .setTextColor(activity.getResources().getColor(
                                R.color.app_azul_claro));
                ((TextView) v.findViewById(R.id.tvNumLike))
                        .setTextColor(activity.getResources().getColor(
                                R.color.app_azul_claro));

                notifyDataSetChanged();

                TrackingManager.trackEvent(ConstantsLab.VOTACAO,
                        ConstantsLab.EVENTO_RESPOSTA_POSITIVA,
                        qa.getQuestion());

                UpDownVoteWsAsyncTask asyncTask = new UpDownVoteWsAsyncTask();
                asyncTask.flagUPDown = 1;
                asyncTask.id = qa.getId();
                asyncTask.execute(ConstantsLab.WS_BASE_URL
                        + ConstantsLab.WS_UP_DOWN_VOTE);
            }
        });

        holder.llDisLike.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                QA qa = getItemQa(position);

                int value = (int) (qa.getDown_count() + 1);
                qa.setDown_count(value);

                qa.setLike(false);
                qa.setWasVoted(true);

                ((LinearLayout) v).setEnabled(false);
                ((LinearLayout) ((LinearLayout) v.getParent())
                        .findViewById(R.id.llLike)).setEnabled(false);
                ((ImageView) v.findViewById(R.id.ivDisLike))
                        .setSelected(true);
                ((TextView) v.findViewById(R.id.tvNaoAjudou))
                        .setTextColor(activity.getResources().getColor(
                                R.color.app_vermelho));
                ((TextView) v.findViewById(R.id.tvNumDisLike))
                        .setTextColor(activity.getResources().getColor(
                                R.color.app_vermelho));

                notifyDataSetChanged();

                TrackingManager.trackEvent(ConstantsLab.VOTACAO,
                        ConstantsLab.EVENTO_RESPOSTA_NEGATIVA,
                        qa.getQuestion());

                UpDownVoteWsAsyncTask asyncTask = new UpDownVoteWsAsyncTask();
                asyncTask.flagUPDown = 0;
                asyncTask.id = qa.getId();
                asyncTask.execute(ConstantsLab.WS_BASE_URL
                        + ConstantsLab.WS_UP_DOWN_VOTE);
            }
        });

        convertView.setTag(holder);

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

    final QA qa = getItemQa(position);

    if (qa != null) {

        String name = qa.getName();
        String city = qa.getCity();
        String state = qa.getState();

        if (qa.getName().equals(null) || qa.getName().equals("null")) {
            name = " ";
        }

        if (qa.getCity().equals(null) || qa.getCity().equals("null")) {
            city = " ";
        }

        if (qa.getState().equals(null) || qa.getState().equals("null")) {
            state = " ";
        }

        holder.tvLocal.setText(activity.getString(
                R.string.local_item_pergunta, name, city, state));

        holder.tvQuestion.setText(qa.getQuestion());
        holder.tvAnswer.setText(qa.getAnswer());

        holder.tvNumLike.setText(String.valueOf(qa.getUp_count()));
        holder.tvNumDisLike.setText(String.valueOf(qa.getDown_count()));

        if (qa.isVisible()) {
            holder.llContainerLikeDislike.setVisibility(View.VISIBLE);
            holder.llContainerLikeDislike.requestLayout();
        } else {
            holder.llContainerLikeDislike.setVisibility(View.GONE);
            holder.llContainerLikeDislike.requestLayout();
        }


        if (qa.isWasVoted()) {
            holder.llLike.setEnabled(false);
            holder.llDisLike.setEnabled(false);
            verifyStatusButtonLikeDisLike(qa);
        } else {
            holder.llLike.setEnabled(true);
            holder.llDisLike.setEnabled(true);
            holder.ivLike.setSelected(false);
            holder.tvAjudou.setTextColor(activity.getResources().getColor(
                    R.color.app_cinza_claro));
            holder.tvNumLike.setTextColor(activity.getResources().getColor(
                    R.color.app_cinza_claro));
            holder.ivDisLike.setSelected(false);
            holder.tvNaoAjudou.setTextColor(activity.getResources()
                    .getColor(R.color.app_cinza_claro));
            holder.tvNumDisLike.setTextColor(activity.getResources()
                    .getColor(R.color.app_cinza_claro));
        }

    }
    return convertView;
}

private void verifyStatusButtonLikeDisLike(final QA qa) {
    if (!qa.isLike()) {
        holder.ivDisLike.setSelected(true);
        holder.tvNaoAjudou.setTextColor(activity.getResources().getColor(
                R.color.app_vermelho));
        holder.tvNumDisLike.setTextColor(activity.getResources().getColor(
                R.color.app_vermelho));
        holder.ivLike.setSelected(false);
        holder.tvAjudou.setTextColor(activity.getResources().getColor(
                R.color.app_cinza_claro));
        holder.tvNumLike.setTextColor(activity.getResources().getColor(
                R.color.app_cinza_claro));
    } else {
        holder.ivLike.setSelected(true);
        holder.tvAjudou.setTextColor(activity.getResources().getColor(
                R.color.app_azul_claro));
        holder.tvNumLike.setTextColor(activity.getResources().getColor(
                R.color.app_azul_claro));
        holder.ivDisLike.setSelected(false);
        holder.tvNaoAjudou.setTextColor(activity.getResources().getColor(
                R.color.app_cinza_claro));
        holder.tvNumDisLike.setTextColor(activity.getResources().getColor(
                R.color.app_cinza_claro));
    }
}

//another methods
//...

    /**
     * {@link AsyncTask} for the send data like or dislike.
     */
    public class MyAsyncTask extends AsyncTask<String, Integer, Boolean>{...}

}
    
asked by anonymous 29.07.2015 / 14:16

0 answers