Android列表视图在滚动时重复显示EditText的值

4

我有一个包含一个textview和一个edit textlistview,每一行都有。如果我在一个编辑文本字段中设置一个值,然后向下滚动,我会在其他一些编辑文本字段中获得该输入字段的重复值。如何解决这个问题?

我的适配器类如下所示:

public class CustomAdapter extends ArrayAdapter<String> {
  private Context       context;
  private String[]  names;
  ViewHolder holder;

  static class ViewHolder {
    public TextView text;
    public EditText editText;
  }

  public CustomAdapter(Context context, int textViewResourceId, String[] names) {
    super(context, textViewResourceId, names);
    this.context = context;
    this.names = names;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.row_design, parent, false);
        holder = new ViewHolder();
        holder.text = (TextView) convertView.findViewById(R.id.textView1);
        holder.editText = (EditText) convertView.findViewById(R.id.editText1);
        convertView.setTag(holder);         
    } else {            
        holder = (ViewHolder) convertView.getTag();
    }

    String s = names[position];
    holder.text.setText(s);
    return convertView;
  }
}

我参考了以下链接: Listview重复操作Android listview滚动时会出现重复的项目

4个回答

5
首先,这个问题的原因是Listview在滚动时重用视图, 因此我们应该在getView中设置一个逻辑来管理它。
if(convertview == null)
{
 //code here 
}else {
 //code here 
}    

但如果您不想重用,则可以使用以下内容:

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

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

这里的500是什么意思,我们能改变它吗?请解释一下。 - Lalit Sharma
如果我们需要在列表视图中显示不同类型的视图,那么最好使用 getViewTypeCount()。如果您只想显示一种类型的视图,可以在此处使用0。 - GOLDEE
如果你真的想使用这个getViewTypeCount hack(非常非常糟糕 - 因为没有回收发生),你应该将getViewTypeCount设置为返回项目的大小... - Marko

0

尝试下面的代码:

public class CustomAdapter extends ArrayAdapter<String> {
  private Context       context;
  private String[]  names;

  static class ViewHolder {
    public TextView text;
    public EditText editText;
  }

  public CustomAdapter(Context context, int textViewResourceId, String[] names) {
    super(context, textViewResourceId, names);
   this.context = context;
    this.names = names;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    View rowView = convertView;
    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rowView = inflater.inflate(R.layout.row_design, parent, null);
        ViewHolder viewHolder = new ViewHolder();
        viewHolder.text = (TextView) rowView.findViewById(R.id.textView1);
        viewHolder.editText = (EditText) rowView.findViewById(R.id.editText1);
        rowView.setTag(viewHolder);         
    }          
        ViewHolder holder = (ViewHolder)rowView.getTag();


    String s = names[position];
    holder.text.setText(s);
    return rowView;
  }
}

欲知详情,请参考此链接

希望对您有所帮助。


0

这是我目前能想到的最好解决方案。但您可以尝试以下解决方法。我同意,可能有更好/更清晰的解决方案来解决这个问题。

您面临的问题是由于ListView为了更好的性能而回收视图。

首先,您可以将数据更改为List而不是数组,并进行以下更改。

List<String> names;
List<String> edit;

// In Constructor()
this.names = names;
// Create a list with empty data for the editTexts
int listSize = names.size();
String emptyString = new String("");
List<String> emptyList = new ArrayList<String>(listSize);
for(int i = 0; i < listSize; i ++){
    emptyList.add(emptyString);
}
this.edit = emptyList;

// In getView()
// add watcher to editText and when it is changed, update the value in 'edit'
// Simply set the corresponding values to this row to the editText
holder.text.setText(names.get(position));
holder.editText.setText(edit.get(position));

你能看看这个解决方案是否能在短期内解决你的问题吗?

你可以从这个答案https://stackoverflow.com/a/11181721/592025中了解如何使用观察器。


0

更新:

我的原始解决方案适用于此用例,但更好的解决方案是使用ViewHolder模式,正如HailNaRoz所提到的那样。虽然HailNaRoz没有解释他的解决方案为什么有效,但该解决方案使用ViewHolder来帮助View重用,并且是Google和Android Dev社区采用的首选方法。 ViewHolder保留对ViewsEditTextTextViewImageView等)的引用,并允许您在其变得可见时将它们添加回正确的列表行中。

还值得看一下RecyclerView,它已经被引入以缓解这些问题,强制执行这种方法。 RecyclerView可作为支持库添加到gradle中。

请参阅ListView中的ViewHolder创建列表和卡片(RecyclerView)

原文:

你的问题是你的EditText被重复使用。你在加载每次视图时保留了TextView文本的副本并进行了重置,但是对于你的EditText没有这样做。

因此,你需要一种方法来存储EditText字段中的文本,并在getView()方法中进行重置。

为了实现这个目标,你可以在getView()方法的if/else语句之后设置一个TextWatcher

holder.editText.addTextChangedListener(new TextWatcher() {

            public void onTextChanged(CharSequence s, int start,
                    int before, int count) {
            }

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

            public void afterTextChanged(Editable s) {
                  editTextList.put(position,s.toString());
            }
        });

这将值存储在单独维护的 HashMap 中。 position 取自您的 getView() 方法中的 int 参数。 您需要将其设置为 final。

HashMap

private HashMap<Integer,String> editTextList =new HashMap<Integer,String>();

然后,当您设置 TextView 文本时,也要设置 EditText 值:
holder.text.setText(s);
holder.editText.setText(editTextList.get(position));

这应该可以保持当前位置editText值在正确的EditText框中。


感谢Biddulph的回复。但是对我来说它不起作用。它对你有用吗? - Akash Patra
1
这个设置对我有效。你尝试过调试并确保进出editTextList的值存在,并且TextWatcher监听器被正确触发了吗? - biddulph.r

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接