Android: проблема с ListViews и CheckBoxes - PullRequest
7 голосов
/ 07 сентября 2010

У меня есть ListView, и внутри каждого элемента списка у меня есть несколько TextViews и CheckBox. Когда я проверяю CheckBox и у меня срабатывает onCheckedChangeListener, все работает как надо. Тем не менее, случайные другие флажки проверяются, если один из них установлен. Вот пример.

Если я нажму на первый CheckBox: 8 проверено. 15 проверено. 21 проверен. 27 проверено. 33 проверено. 41 проверен. Затем, если я прокручиваю весь путь вверх, ни один не проверяется до 6. Следующее будет 13.

В основном ... что происходит?

Ответы [ 6 ]

10 голосов
/ 07 сентября 2010

Похоже, что вы повторно используете convertView, который передается реализуемым вами методом getView().

Android будет пытаться использовать один и тот же вид для разных элементов в ListView. Вам либо нужно (1) снять / проверить вручную флажок, который находится внутри возвращаемого элемента (всегда вызывайте setChecked перед возвратом в getView, либо (2) не использовать convertView, но вернуть новый вид из getView.

(1) рекомендуется, я думаю.

6 голосов
/ 04 августа 2011

отлично работает у меня

public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {

        final ViewHolder holder;
        final Season season = (Season) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = vi.inflate(R.layout.season, parent, false);
            holder = new ViewHolder();
            holder.title = (TextView) convertView.findViewById(R.id.season_title);
            holder.checkBox = (CheckBox) convertView.findViewById(R.id.season_check_box);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.title.setText(season.getTitle());
        holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                season.setChecked(isChecked);
                adapter.notifyDataSetChanged();
            }
        });

        holder.checkBox.setChecked(season.isChecked()); // position is important! Must be before return statement!
        return convertView;
    }

    protected class ViewHolder {
        protected TextView title;
        protected CheckBox checkBox;
    }
0 голосов
/ 15 февраля 2018
@Override
public int getViewTypeCount() {
    return getCount();
}

@Override
public int getItemViewType(int position) {
    return position;
}

@Override
public int getCount() {
    return names.length;
}

@Override
public long getItemId(int position) {
    return 0;
}

добавить этот метод в пользовательский адаптер. это работает для меня

0 голосов
/ 18 августа 2015

У меня была такая же проблема с моим представлением переключателя.После долгих поисков и прочтений я выяснил, что эта проблема является результатом своего рода оптимизации представлений, продвигаемых Android.Попытка повторно использовать виды объектов.Таким образом, в основном, когда вы нажимаете на переключатель или флажок, вы запускаете обратный вызов изменений и в другом представлении.Оптимизация действительно работает, но если вы не обращаете внимания или просто не знаете, как себя вести (например, я), происходят довольно странные результаты.

В любом случае, я нахожу это простое решение:

Рекомендуется повторно использовать convertView, переданный методу getView ().Таким образом вы оптимизируете количество оперативной памяти, используемое списком.Поэтому я храню свои представления в ViewHolder и программирую событие onCheckedChanged.Хитрость заключается в том, что перед установкой, если переключатель проверен или нет (в вашем случае, установите флажок) и определите прослушиватель CheckedChange, я просто сбрасываю обратный вызов с нулем, это гарантирует, что событие другого переключателя не будет запущено.1005 *

Вот фрагмент:

...
viewHolder.switchView.setOnCheckedChangeListener(null);
viewHolder.switchView.setChecked(myObject.getStatus() > 0);
...
viewHolder.switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                ...
            }
        });

myObject - это конечный объект, в котором хранятся данные курсора.

И независимо от того, будет ли переключатель проверен или нет, у вас естьвызвать метод setChecked.

Надеюсь, это кому-нибудь поможет!

0 голосов
/ 05 февраля 2014

Эту проблему можно легко решить, сохранив CheckBox состояния.Самоопределенный и объясненный полный код класса образца для того же кода приведен ниже:

 public class AreaDataAdapter extends ArrayAdapter<String> {
    private List<String> areaList;
    private Activity context;
    ArrayList<Boolean> positionArray;

    public AreaDataAdapter(Context context, int textViewResourceId,
            List<String> offersAreaList) {
        super(context, textViewResourceId, offersAreaList);
        // TODO Auto-generated constructor stub
        this.context=context;
        this.areaList = offersAreaList;

         positionArray = new ArrayList<Boolean>(offersAreaList.size());
            for(int i =0;i<offersAreaList.size();i++){
                positionArray.add(false);
          }

    }

    public AreaDataAdapter(Activity context, List<String> offersAreaList) {
        super(ShowOffersActivity.this, R.layout.filterlist_row, offersAreaList);
        this.context=context;
        this.areaList=offersAreaList;

         positionArray = new ArrayList<Boolean>(offersAreaList.size());
            for(int i =0;i<offersAreaList.size();i++){
                positionArray.add(false);
          }

    }

    public View getView(final int position, View convertView,ViewGroup parent) {
        View row=convertView;
        FilterViewHolder holder;
        if (row==null) {
            LayoutInflater inflater=getLayoutInflater();

            row=inflater.inflate(R.layout.filterlist_row, parent, false);
            holder = new FilterViewHolder();
            holder.filterCheckBox = (CheckBox)row.findViewById(R.id.filter_checkbox);
            holder.filterCheckBox.setTypeface(fontFace);

            row.setTag(holder);
        } else {
            //holder = (View) row;
            holder = (FilterViewHolder) row.getTag();

            /* When a listview recycles views , it recycles its present state as well as listeners attached to it.
             * if the checkbox was checked and has a onCheckedChangeListener set, both will remain a part of 
             * recycled view based on position. So it is our responsibility to reset all states and remove
             *  previous listeners.
             *  The listener was removed as below:-
             */
            holder.filterCheckBox.setOnCheckedChangeListener(null);

        }

            holder.filterCheckBox.setText(areaList.get(position));
            holder.filterCheckBox.setFocusable(false);
            holder.filterCheckBox.setChecked(positionArray.get(position));
            holder.filterCheckBox.setText(areaList.get(position));

            holder.filterCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    // TODO Auto-generated method stub
                    if (isChecked) {
                        //change state of concern item in 'positionArray' array to 'True'
                         positionArray.set(position, true);
                        //add the checked item in to area list which used to filter offers.
                        filterOffersByThisAreaList.add(areaList.get(position));

                    } else {
                       //change state of concern item in 'positionArray' array to 'True'
                         positionArray.set(position, true);
                        //remove the unchecked item in to area list which used to filter offers.
                        filterOffersByThisAreaList.remove(areaList.get(position));

                    }
                }
            });
        return row;
    }

}

Пользовательская строка (filterlist_row) для ListView Содержит эти CheckBox с, как показано ниже

1009

настроить CheckBox фон, как показано ниже

1013 *
0 голосов
/ 01 февраля 2012

Я также столкнулся с подобным королем проблемы, поэтому после долгих чтений я решил эту проблему следующим образом:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.listview, null);
            holder = new ViewHolder();
            holder.nameView = (TextView)convertView.findViewById(R.id.textView1);
            holder.numberView = (TextView)convertView.findViewById(R.id.textView2);
            holder.cb = (CheckBox)convertView.findViewById(R.id.checkBox1);
            convertView.setTag(holder);                
        } else {
            holder = (ViewHolder)convertView.getTag();
        }
        holder.nameView.setText(mData.get(position).toString());
        holder.numberView.setText(mNumber.get(position).toString());
        holder.cb.setChecked(false);
        holder.cb.setTag(position);



        if(selected.indexOf(mNumber.get(position).toString()) >= 0) // Check whether this row checkbox was checked, for that we previously stored the textview text in selected variable
        {

        holder.cb.setChecked(true);
        }

        return convertView;
    }

}

Вот что я делаю, что в getView () я снимаю все флажкии проверяя снова вручную те, которые мне нужно проверить в соответствии с просмотром текста, который он соответствует.Таким образом, если пользователь прокрутит вниз после установки первого флажка, все флажки в представлении будут сняты, и если он снова прокрутится вверх, то также все флажки будут сняты, но затем тот, который он щелкнул ранее, будет снова проверен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...