htz
htz

Reputation: 1037

how to save state of view in listview

In my app, I display a check list using a ListView. Every row in my check list is represented by a model, which is an object of the ChecklistenPunkt class. There are three different types of rows:

  1. a headline
  2. an additional text
  3. a question

The third type has two Buttons in it which are linked by two OnClickListeners: The first Button is for a positive answer, the second one for a negative answer. When the view is build, both of them are gray, indicating that this question is not yet answered. If the left Buttonis clicked it turns green and the second one is getting a dark gray background. If the right Button is clicked it turns red and the first one is getting a dark gray background. When a Button is clicked the answering state is saved as an ChecklistenPunktStatus. This is an Enum which has three entries (okay, not okay, not answered).

Here is a little image of the Buttons in three rows, showing the different states:

enter image description here

Here is my adapter code:

public class ChecklisteAdapter extends ArrayAdapter<Object> {

    private List<ChecklistenPunkt> list;
    private SparseArray<ChecklistenPunktStatus> sparseArray;
    private Context context;

    public ChecklisteAdapter(Context context, List<ChecklistenPunkt> objects) {
        super(context, 0);
        list = objects;
        sparseArray = new SparseArray<ChecklistenPunktStatus>();
        for (int i = 0; i < list.size(); i++) {
            sparseArray.put(i, ChecklistenPunktStatus.NICHT_SELEKTIERT);
        }
        this.context = context;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public ChecklistenPunkt getItem(int position) {
        return list.get(position);
    }

    @Override
    public int getItemViewType(int position) {
        ChecklistenPunkt p = (ChecklistenPunkt) list.get(position);
        return p.getTyp();
    }

    @Override
    public int getViewTypeCount() {
        return 3;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View v = null;
        int type = getItemViewType(position);
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            final ViewHolder viewHolder = new ViewHolder();
            switch (type) {
                case Util.CHECKLISTE_FRAGE:
                    v = inflater.inflate(R.layout.pruefung_durchfuehren_list_item_frage, null);
                    viewHolder.nummer = (TextView) v.findViewById(R.id.check_nummer);
                    viewHolder.komponente = (TextView) v.findViewById(R.id.check_komponente);
                    viewHolder.funktion = (TextView) v.findViewById(R.id.check_funktion);
                    viewHolder.kriterium = (TextView) v.findViewById(R.id.check_kriterium);
                    viewHolder.erlaeuterung = (TextView) v.findViewById(R.id.check_erlaeuterung);
                    viewHolder.io = (Button) v.findViewById(R.id.button_i_o);
                    viewHolder.nio = (Button) v.findViewById(R.id.button_n_i_o);
                    viewHolder.io.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            viewHolder.io.setBackgroundColor(Color.GREEN);
                            viewHolder.io.setEnabled(false);
                            viewHolder.nio.setBackgroundColor(Color.GRAY);
                            viewHolder.nio.setEnabled(true);
                            sparseArray.put(position, ChecklistenPunktStatus.IN_ORDNUNG);
                        }
                    });
                    viewHolder.nio.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            viewHolder.nio.setBackgroundColor(Color.RED);
                            viewHolder.nio.setEnabled(false);
                            viewHolder.io.setBackgroundColor(Color.GRAY);
                            viewHolder.io.setEnabled(true);
                            sparseArray.put(position, ChecklistenPunktStatus.NICHT_IN_ORDNUNG);
                        }
                    });
                    ChecklistenPunktStatus status = sparseArray.get(position);
                    if (status == ChecklistenPunktStatus.IN_ORDNUNG) {
                        viewHolder.io.setBackgroundColor(Color.GREEN);
                        viewHolder.io.setEnabled(false);
                        viewHolder.nio.setBackgroundColor(Color.GRAY);
                        viewHolder.nio.setEnabled(true);
                    } else if (status == ChecklistenPunktStatus.NICHT_IN_ORDNUNG) {
                        viewHolder.nio.setBackgroundColor(Color.RED);
                        viewHolder.nio.setEnabled(false);
                        viewHolder.io.setBackgroundColor(Color.GRAY);
                        viewHolder.io.setEnabled(true);
                    } else if (status == ChecklistenPunktStatus.NICHT_SELEKTIERT) {
                        viewHolder.nio.setBackgroundColor(Color.parseColor("#cccccc"));
                        viewHolder.nio.setEnabled(true);
                        viewHolder.io.setBackgroundColor(Color.parseColor("#cccccc"));
                        viewHolder.io.setEnabled(true);
                    }

                    v.setTag(viewHolder);
                    break;
                case Util.CHECKLISTE_UEBERSCHRIFT:
                    v = inflater.inflate(R.layout.pruefung_durchfuehren_list_item_head, null);
                    viewHolder.headline = (TextView) v.findViewById(R.id.check_headline);
                    viewHolder.headnummer = (TextView) v.findViewById(R.id.check_headnummer);
                    v.setTag(viewHolder);
                    break;
                case Util.CHECKLISTE_ZUSATZTEXT:
                    v = inflater.inflate(R.layout.pruefung_durchfuehren_list_item_text, null);
                    viewHolder.text = (TextView) v.findViewById(R.id.check_text);
                    viewHolder.textnummer = (TextView) v.findViewById(R.id.check_textnummer);
                    v.setTag(viewHolder);
                    break;
                default:
                    throw new IllegalArgumentException("ViewType " + type + " unbekannt!");
            }
        } else {
            v = convertView;
        }

        ChecklistenPunkt clp = getItem(position);
        ViewHolder viewHolder = (ViewHolder) v.getTag();
        if (clp != null) {
            switch (type) {
                case Util.CHECKLISTE_FRAGE: {
                    viewHolder.nummer.setText(clp.getNummer());
                    viewHolder.komponente.setText(clp.getKomponente());
                    viewHolder.funktion.setText(clp.getFunktion());
                    viewHolder.kriterium.setText(clp.getKriterium());
                    viewHolder.erlaeuterung.setText(clp.getErlaeuterung());
                    ChecklistenPunktStatus status = sparseArray.get(position);
                    if (status == ChecklistenPunktStatus.IN_ORDNUNG) {
                        viewHolder.io.setBackgroundColor(Color.GREEN);
                        viewHolder.io.setEnabled(false);
                        viewHolder.nio.setBackgroundColor(Color.GRAY);
                        viewHolder.nio.setEnabled(true);
                    } else if (status == ChecklistenPunktStatus.NICHT_IN_ORDNUNG) {
                        viewHolder.nio.setBackgroundColor(Color.RED);
                        viewHolder.nio.setEnabled(false);
                        viewHolder.io.setBackgroundColor(Color.GRAY);
                        viewHolder.io.setEnabled(true);
                    } else if (status == ChecklistenPunktStatus.NICHT_SELEKTIERT) {
                        viewHolder.nio.setBackgroundColor(Color.parseColor("#cccccc"));
                        viewHolder.nio.setEnabled(true);
                        viewHolder.io.setBackgroundColor(Color.parseColor("#cccccc"));
                        viewHolder.io.setEnabled(true);
                    }
                    break;
                }
                case Util.CHECKLISTE_UEBERSCHRIFT: {
                    viewHolder.headline.setText(clp.getHeadline());
                    viewHolder.headnummer.setText(clp.getNummer());
                    break;
                }
                case Util.CHECKLISTE_ZUSATZTEXT: {
                    viewHolder.text.setText(Html.fromHtml(clp.getZusatz()));
                    viewHolder.textnummer.setText(clp.getNummer());
                    break;
                }
                default:
                    throw new IllegalArgumentException("ViewType " + type + " unbekannt!");
            }
        }
        return v;
    }

    public SparseArray<ChecklistenPunktStatus> getSparseArray() {
        return sparseArray;
    }

    static class ViewHolder {
        protected TextView nummer;
        protected TextView komponente;
        protected TextView kriterium;
        protected TextView funktion;
        protected TextView erlaeuterung;
        protected TextView text;
        protected TextView textnummer;
        protected TextView headline;
        protected TextView headnummer;
        protected Button io;
        protected Button nio;
    }
}

EDIT:

When the convertView is null, I create a new View by inflating my layout. Then I create a new ViewHolder, find the different TextViews and Buttons according to the Views viewType and put them into the ViewHolder. After that, I set this ViewHolder as the tag of the View. I distinguish according to the viewType again and set the text and Listeners of the Views inside the ViewHolder. Then I return the view.

When the convertView is not null I reuse the View. I get the ViewHolder with the getTag() method, set the text and Button state according to the model class and return the view at the end of the method.

My problem is that the answering state is correctly saved in the SparseArray, but it is not displayed correctly. When I answer a question in the first rows of my list and then scroll down, answered questions appear at the end of the list. By scrolling up and down I can mess up the answering states completely. But while this is happening, the states in the sparseArray are always correct.

Am I missing something here?

Upvotes: 0

Views: 229

Answers (1)

alecnash
alecnash

Reputation: 1768

I suppose there is something wrong with the code. When you use the same cell and when the view is not null you should reuse the same holder and not the convertView. Something like that:

ViewHolder viewHolder = new ViewHolder();
if (convertView == null) {
    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    .
    .
    .
} 
else {
    viewHolder = convertView.getTag();
}

Upvotes: 1

Related Questions