【问题标题】:ListView EditTexts values are messed up when scrolling滚动时 ListView EditText 值混乱
【发布时间】:2014-12-18 06:00:21
【问题描述】:

正如我在标题中提到的,列表视图在我的代码的 for 循环中为 i=10 之后的子项复制了 edittexts 值。

public class ExerciseAdapter extends ArrayAdapter<ExerciseSet> {
    private ArrayList<ExerciseSet> mExercise;
    private LayoutInflater inflater;

    private List<String> texts = new ArrayList<String>();

    public ExerciseAdapter(Context context, int textViewResourceId, ArrayList<ExerciseSet> objects) {
        super(context, textViewResourceId, objects);
        mExercise = objects;
        inflater = (LayoutInflater) getContext().
                getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getItemViewType(int position) {
        if(mExercise.get(position).isSet() == false) return 0;
        else return 1;
    }

    @Override
    public int getViewTypeCount() {
        return 2; // two types of rows, exercise headers and bodies (sets)
    }


    public View getView(final int position, View convertView, ViewGroup parent){
        View view = convertView;
        final Holder holder;

        for(int i = 0; i < mExercise.size(); i++) {
            texts.add(String.valueOf(i));
        }

        if (getItemViewType(position) == 0) {

            if (view == null) {

                view = inflater.inflate(R.layout.item_exercise_header, null);
                holder = new Holder();


                holder.exerciseTitleView = (TextView) view.findViewById(R.id.tv_exercice_title);
                view.setTag(holder);

            } else {

                holder = (Holder) convertView.getTag();
            }
            ExerciseSet exercise = mExercise.get(position);

            if (exercise != null)
                holder.exerciseTitleView.setText(exercise.getExerciseTitle());


        } else {

            if (view == null) {
                view = inflater.inflate(R.layout.item_set, null);
                holder = new Holder();

                holder.setCounterView = (TextView) view.findViewById(R.id.tv_set_counter);

                holder.cbSet = (CheckBox) view.findViewById(R.id.cb_setdone);

                holder.repsCapt = (EditText) view.findViewById(R.id.et_reps_number);

                holder.repsCapt.setTag(position); 

                holder.repsCapt.setText(texts.get(position));

                //holder.weightCapt = (EditText) view.findViewById(R.id.et_weight_number);

                //db = new DatabaseHandler(this.getContext());

                //holder.weightCapt.setTag(position);
                view.setTag(holder);

            } else {

                holder = (Holder) convertView.getTag();

            }
            ExerciseSet exercise = mExercise.get(position);

            /*
             * edit texts
             */
            int tag_position=(Integer) holder.repsCapt.getTag();
            holder.repsCapt.setId(tag_position);

            holder.repsCapt.addTextChangedListener(new TextWatcher() {

                   @Override
                   public void onTextChanged(CharSequence s, int start, int before,
                           int count) {
                             final EditText repsText = (EditText) holder.repsCapt;

                             if(repsText.getText().toString().length()>0){
                                 texts.add(repsText.getText().toString());
                             }else{
                                 Toast.makeText(getContext(), "Please enter some value", Toast.LENGTH_SHORT).show();
                             }

                         }

                   @Override
                   public void beforeTextChanged(CharSequence s, int start, int count,
                           int after) {
                       // TODO Auto-generated method stub
                   }

                   @Override
                   public void afterTextChanged(Editable s) {

                   }

               });

            if (exercise != null) {
                holder.setCounterView.setText(String.valueOf(exercise.getSetId()));
            }


            /*
             * check boxes 
             */

            holder.cbSet.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton button, boolean isChecked) {

                    if(isChecked)
                        mExercise.get(position).setCbChecked(true);
                    else
                        mExercise.get(position).setCbChecked(false);
                }
            });

            holder.cbSet.setChecked(exercise.isCbChecked());

        }

        return view;
    }

    static class Holder {
        public EditText weightCapt;
        public EditText repsCapt;

        // header row items
        TextView exerciseTitleView;

        // body row item
        CheckBox cbSet;
        TextView setCounterView;
    }

}

我不知道为什么,请帮忙..

Edit_1:我尝试将值保存到数组列表中并在重用视图时检索它们,但当我向下滚动时它仍然给我重复的值。

Edit_2:如果我的问题不清楚,请告诉我!

Edit_3:我将 holder.repsCapt.setText(texts.get(position)) 放在 if (exercise != null) { 条件内,并且值不再重复。但是,如果我向下和向上滚动,值会变得混乱。

【问题讨论】:

  • 也许这个holder.repsCapt.addTextChangedListener(new TextWatcher() { 每次视图被回收时都会有旧的监听器,然后你添加另一个监听器。基本上答案是回收视图,您只需要找出回收导致您的问题的原因
  • 你是对的 Blundell,我只是认为它可能会起作用,因为它与 CheckBoxes 一起使用,我认为存在差异。我现在把全班都贴出来了,你能看一下吗?也许你能想出一个解决办法。
  • CheckboxsetOnCheckedChangeListener,另一个是addTextChangedListener。注意细微的命名差异。 set 表示将其设置为这个侦听器并覆盖前一个侦听器 add 表示将另一个侦听器添加到侦听器列表(集合)中
  • 我明白了。你觉得我具体应该怎么做?在这种情况下是否可以替代 addTextChangedListener 服务?
  • 我实在想不出一个不错的答案。你的名单有多大?如果您在每次解决问题时都扩充新视图,请查看是否有任何明显的性能损失

标签: android listview android-edittext


【解决方案1】:

您的问题肯定与列表重用的项目视图有关。
因此,请检查您的条件并确保在所有情况下都提供替代文本。
让我们开始像这样从 item type==0 开始:

if (exercise != null)
                    holder.exerciseTitleView.setText(exercise.getExerciseTitle());

添加

else
    holder.exerciseTitleView.setText("debugging: nothing to show");


编辑
关于 type==1 也是一样:
- holder.repsCapt.setText(texts.get(position)) 仅在新膨胀的视图上调用
- holder.setCounterView.setText(String.valueOf(exercise.getSetId())) 仅当 excersise 不为空时

编辑2
好吧,出于DEBUG 的目的,尽量不要重用getView() 中的视图 - 总是 从一开始就膨胀。

如果一切正常(或者你得到一些空白字段),那么回到我在这篇文章中最初的建议。我怀疑这种情况

如果问题仍然存在,则应注意根据位置正确获取数据。

【讨论】:

  • 实际上问题是项目类型==1的EditTexts。 listView 复制了我的 editTexts 值..
  • 我将holder.repsCapt.setText(texts.get(position)) 放在if (exercise != null) { 条件内,并且不再重复这些值。但是,如果我向下和向上滚动值会变得混乱,您是否也知道如何解决这个问题?
  • 当我向下滚动时,您知道如何防止值混乱吗?
  • 你的意思是我必须在构造函数中充气吗?如果是这样的话,那么我不知道该怎么做,我有两种观点。如果不能,请您说的更具体些吗?
  • 否,在 getView() 中且仅用于调试。现在你有条件地膨胀: if (view == null) { view = inflater.inflate(R.layout.item_exercise_header, null); ...
【解决方案2】:

在 google 一番挖掘之后,我设法解决了我的问题,结果如下:

@SuppressWarnings("unused")
@Override
public View getView(final int position, View convertView, ViewGroup arg2) {
    final Holder holder;
    convertView = null;
    if(getItemViewType(position) == 0) {
    if (convertView == null) {

        convertView = inflater.inflate(R.layout.item_exercise_header, null);
            holder = new Holder();
            holder.exerciseTitleView = (TextView)               convertView.findViewById(R.id.tv_exercice_title);
        convertView.setTag(holder);

        } else {

            holder = (Holder) convertView.getTag();
        }
        ExerciseSet exercise = exerciseList.get(position);

        if (exercise != null)
            holder.exerciseTitleView.setText(exercise.getExerciseTitle());

     }
     else if (getItemViewType(position) == 1) { 
     if (convertView == null) {
        holder = new Holder();

                convertView = inflater.inflate(R.layout.item_set, null);

                // reps e.t
                holder.repsCapt = (EditText) convertView
                        .findViewById(R.id.et_reps_number);

                holder.repsCapt.setTag(position);

                // weight e.t
                if(exerciseList.get(position).getExerSave()!=null) {
                    holder.repsCapt.setText(exerciseList.get(position).getExerSave().getReps());

                }
                // t.v
                holder.setCounterView = (TextView) convertView.findViewById(R.id.tv_set_counter);

                // c.b
                holder.cbSet = (CheckBox) convertView.findViewById(R.id.cb_setdone);

                convertView.setTag(holder);

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

            /*
             * text views
             */
            ExerciseSet exercise = exerciseList.get(position);

            if (exercise != null) {
                holder.setCounterView.setText(String.valueOf(exercise.getSetId()));
            }

            /* 
             * edit texts
             */
            int tag_position=(Integer) holder.repsCapt.getTag();

            holder.repsCapt.setId(tag_position);

            holder.repsCapt.addTextChangedListener(new TextWatcher() {

               @Override
               public void onTextChanged(CharSequence s, int start, int before,
                       int count) {
                   final int position2 = holder.repsCapt.getId();
                   final EditText repsText = (EditText) holder.repsCapt;
                   if(repsText.getText().toString().length()>0){
                       Save sv;

                       ExerciseSet es = exerciseList.get(position2);
                       if(es.getExerSave() != null)
                           sv = es.getExerSave();
                       else sv = new Save();

                       sv.setSet(position2);
                       sv.setReps(repsText.getText().toString());

                       es.setExerSave(sv);
                       exerciseList.set(position2,es);
                   }
               }

               @Override
               public void beforeTextChanged(CharSequence s, int start, int count,
                       int after) {

               }

               @Override
               public void afterTextChanged(Editable s) {

               }
            });

            /*
             * checkboxes
             */
            holder.cbSet.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton button, boolean isChecked) {

                    if(isChecked)
                        exerciseList.get(position).setCbChecked(true);
                    else
                        exerciseList.get(position).setCbChecked(false);
                }
            });

            holder.cbSet.setChecked(exercise.isCbChecked());    
        }
        return convertView;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    • 2015-12-10
    • 1970-01-01
    相关资源
    最近更新 更多