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的行(没有滚动),这是可以的,否则这个黑客是可怕的。 您应该手动处理数据