EditText在ListView中滚动时丢失内容

我有EditText列表项目,我不知道会有多less项目。 当我在EditText中input一些文本时出现问题,然后向下滚动ListView,再次向上滚动后,我的第一个EditText中没有文本,或者ListView中的其他EditText有一些文本。

我已经尝试了TextWatcher,并将数据保存到数组,但问题是在ListView中返回的视图位置总是正确的,所以我从数组中丢失了一些数据。 -.-

如何在ListView中检测正确的视图位置?

例如:

如果我在ListView中有10个项目,并且只有5个当前可见。 适配器返回的位置从0到4 …没关系。 当我向下滚动项目6的位置是0 … wtf? 和我失去arrays上的位置0的数据:)

我使用ArrayAdapter。

请帮忙。

这是一些代码:

public View getView(int position, View convertView, ViewGroup parent) { tmp_position = position; if (convertView == null) { holder = new ViewHolder(); LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = vi.inflate(R.layout.element_in_game, null); holder.scoreToUpdate = (EditText) convertView .findViewById(R.id.elementUpdateScore); holder.scoreToUpdate.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { scoresToUpdate[tmp_position] = s.toString(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } }); initScoresToUpdateEditTexts(holder.scoreToUpdate, hint); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); holder.scoreToUpdate.setText(scoresToUpdate[tmp_position]); } return convertView; } 

你应该这样尝试,如下所示:

 if (convertView == null) { holder = new ViewHolder(); LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = vi.inflate(R.layout.element_in_game, null); holder.scoreToUpdate = (EditText) convertView .findViewById(R.id.elementUpdateScore); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } //binding data from array list holder.scoreToUpdate.setText(scoresToUpdate[position]); holder.scoreToUpdate.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { //setting data to array, when changed scoresToUpdate[position] = s.toString(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } }); return convertView; } 

说明:ListView的回收行为,实际上清除了所有与其Row项绑定的数据,出于视觉时。 所以每一个新的行都可以从任何方向进入视觉,再次绑定数据。 另外,当EditText文本更改时,还必须在某些数据结构中保留值,因此,稍后再次进行行数据绑定时,可以提取数据以获取位置。 你可以使用数组ArrayList来保存edittext数据,也可以用来绑定数据。

在Recyclerview Adapter中使用类似的行为,在适配器的行数据的数据绑定需要了解的逻辑背后。

你可以使用setOnFocusChangeListener来代替。 在我的情况下,我有可扩展列表,它似乎很好:)像这样:

 holder.count.setOnFocusChangeListener(new View.OnFocusChangeListener() { public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { EditText et =(EditText)v.findViewById(R.id.txtCount); myList.get(parentPos).put(childPos, et.getText().toString().trim()); } } }); 

如果你只有10行,不要打扰ListView 。 只要将它们放在一个垂直的LinearLayout中,并将其包装在一个ScrollView ,它会为您节省一些头痛的问题。

如果你要有几十或几百行,我build议你在ListView行中提供比EditText小部件更好的UX范例。

所有这一切说,感觉就像你没有正确处理你的行回收,或不知道行被回收。 如果您的ListAdapter有10个项目,并且只有空间可以显示带有EditText小部件的5行,则当用户滚动到底部时,不应该包含10个EditText小部件。 你应该用5-7 – 在屏幕上的结果,当用户下一次滚动时,可能还有一到两个用于回收。

从我的一本书的 免费摘录经历了创buildArrayAdapter自定义子类和获得回收工作的过程。 它还涵盖了一个交互式行,使用RatingBar作为用户input。 这比EditText容易得多,因为所有你必须担心的是点击事件。 欢迎您尝试使用EditText小部件和TextWatcher侦听器来扩展该技术,但我不是粉丝。

我有一个相关的问题,我解决了。 我的ListView每一行都有一个不同的视图(它包含不同的控件,EditView,ImageView,TextView)。 即使控件从屏幕滚动出来,我也希望在这些控件中input或select的数据保持不变。 我使用的解决scheme是像这样在ArrayAdapter实现以下方法:

 public int getViewTypeCount() { return getCount(); } public int getItemViewType(int position) { return position; } 

这将确保当getView()被调用时,它将传递在第一次调用时从getView()返回的同一个View实例。

 public View getView(int position, View convertView, ViewGroup parent) { if (convertView != null) return convertView; else // create new view } 

我刚刚在寻找一个类似的解决scheme,发现使用textChangeListener不是最好的方法。 我在这里回答了一个相关问题:

https://stackoverflow.com/a/13312282/1812518

这是我的第一篇文章,但我希望它是有帮助的。

从你的代码的简短摘要看来,你似乎对付回收站。 当您在列表视图中从位置1滚动到位置20时,它不会创build列表视图项目视图的20个不同实例。 相反,它有7或8当一个滚动屏幕,它被添加到回收站,然后作为convertView参数发送到getView方法,所以你可以重新填充新的数据,而不是浪费地创build一个新的视图。

传统上使用ViewHolder模式来保存列表项目(textview,imageview等)的子视图,而不是数据(设置和获得持有人内的得分) – 发生什么事情是你在零位置零值,向下滚动到5个项目屏幕上的第6个项目,第0个项目被重新用于位置6,并且从附加到该列表项目的持有者(在这种情况下为0)

简单的答案:不要在持有人存储位置特定的数据! 将其存储在某个外部数组或散列表中。

更好的方法是在运行时创buildEditText并将其id设置为位置参数

getView()方法。 所以现在当添加文本时,将其存储在一个Vectorvariables(类

variables),并在基于位置variables的getView方法中设置Text(你可以

得到相应的EditText的elementAt()方法)。

不要忘了将这个EditText添加到虚拟的View中。

此代码将帮助你

 private class EfficientAdapter extends BaseAdapter { private LayoutInflater mInflater; private String[] attitude_names; public String[] attitude_values; private String name; public static HashMap<Integer,String> myList=new HashMap<Integer,String>(); public EfficientAdapter(Context context) { mInflater = LayoutInflater.from(context); attitude_names = context.getResources().getStringArray(R.array.COMP_ATTITUDE_NAME); attitude_values = new String[attitude_names.length]; } // initialize myList for(int i=0;i<attitude_names.length;i++) { myList.put(i,""); } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(R.layout.addcomp_attitude_row, null); holder = new ViewHolder(); holder.Attitude_Name = (TextView) convertView.findViewById(R.id.addcomp_att_name); holder.Attitude_Value = (EditText) convertView.findViewById(R.id.addcomp_att_value); holder.Attitude_Value.addTextChangedListener(new TextWatcher() { public void afterTextChanged(Editable edt) { myList.put(pos,s.toString.trim()); attitude_values[holder.ref] = edt.toString(); } public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {} public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { //attitude_values[ref] = Attitude_Value.getText().toString(); } }); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.ref=position; holder.Attitude_Name.setText(attitude_names[position]); holder.Attitude_Value.setHint(attitude_names[position]); holder.Attitude_Value.setText(myList.get(position)); return convertView; } class ViewHolder { TextView Attitude_Name; EditText Attitude_Value; int ref; } @Override public int getCount() { return attitude_names.length; } } 

在这里,我已经包含了一个HashMap对象,它将继续关注EditText包含的值。当您滚动ListView时,它将通过调用其getView方法再次呈现。

在这个代码中,当你第一次加载列表视图时,所有的编辑文本都将没有文本。一旦你input了一些文本,它会在myList中注明。所以当你再次渲染列表时,你的文本将被阻止。

获取convertView == null检查的convertView == null ,它是其他语句。 您的performance会变差,但会禁用回收。

我的适配器扩展了BaseAdapter,而且我有一个类似的情况,就像bickster在那里有列表视图,在这个列表视图中有不同的视图(一种dynamic的forms,如情况),并且需要保存数据。 我的列表视图不会太大,所以回收视图在我的情况下不会是一个很大的资源消耗,因此简单

if (convertView != null) return convertView;

getView的开始对我来说已经足够了。 不知道它有多高效的解决scheme,但这正是我所期待的。

重要编辑: 只有当你有很less的行(没有滚动),这是可以的,否则这个黑客是可怕的。 您应该手动处理数据