滚动时,ListView 中的 EditText 通过 onTextChanged 进行更新。

7

我一直在寻找答案,但是这些解决方案似乎对我无效。 我在列表项中有一个TextView和一个EditText。 当用户编辑EditText时,我正在尝试更新EditText的存储值。

@Override
public View getView(int index, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    final int pos = index;
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.user_details_list_row, parent,false);
        holder = new ViewHolder();
        holder.mCaptionTextView  = (TextView)convertView.findViewById(id.user_detail_row_caption);
        holder.mDetailEditText = (EditText)convertView.findViewById(id.user_detail_row_value);
        convertView.setTag(holder);
    }else{
        holder = (ViewHolder) convertView.getTag();
    }

    holder.mDetailEditText.addTextChangedListener(new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }

        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {              
            mUserDetails.set(pos, s.toString());
        }
    });     

    holder.mCaptionTextView.setText(mUserCaptions.get(index));
    holder.mDetailEditText.setText(mUserDetails.get(index),BufferType.EDITABLE);

    return convertView;
}

public static class ViewHolder{
    public TextView mCaptionTextView;
    public EditText mDetailEditText;
}

当我这么做时,滚动会触发TextWatcher并更新值,用其他EditText中的重复文本覆盖正确的文本。
除了TextWatcher外,我还尝试了以下代码:
holder.mDetailEditText.setOnFocusChangeListener(new OnFocusChangeListener() {

@Override
public void onFocusChange(View v, boolean hasFocus) {
    if (!hasFocus){
        EditText et =   (EditText)v.findViewById(id.user_detail_row_value);
        mUserDetails.set(index, et.getText().toString().trim());
    }
}
});

它还会更新错误的EditText。我在这里错过了什么?

编辑:也尝试过这个:

        final ViewHolder testHolder = holder; 
    holder.mDetailEditText.setOnFocusChangeListener(new OnFocusChangeListener() {

        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus){
                EditText et =   (EditText)v.findViewById(id.user_detail_row_value);
                mUserDetails.set(testHolder.ref, et.getText().toString().trim());
            }
        }
    });

它修正了我看到的滚动变化问题,但现在在编辑其中一个EditText后,它也会更改其他一些EditText。

3个回答

36

问题与您没有从EditText小部件中删除先前添加的文本观察器有关。相反,您不断将新的观察器附加到列表中。一旦您尝试编辑小部件内容,所有文本观察器都会顺序通知,导致更新错误的用户详细信息。

EditText/TextView没有提供一种方法来删除先前添加的文本观察器,而不必拥有对它们的显式引用。这意味着您将不得不重新构建代码,以保留对文本观察器的引用,并为每个getView方法执行创建/添加/删除观察器,或者扩展TextWatcher,允许修改用户详细信息以便在被触发后更新。后者在下面实现了。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.user_details_list_row, parent,false);
        holder = new ViewHolder();
        holder.mCaptionTextView  = (TextView)convertView.findViewById(id.user_detail_row_caption);
        holder.mWatcher = new MutableWatcher();
        holder.mDetailEditText = (EditText)convertView.findViewById(id.user_detail_row_value);
        holder.mDetailEditText.addTextChangedListener(holder.mWatcher);
        convertView.setTag(holder);
    } else{
        holder = (ViewHolder) convertView.getTag();
    }

    holder.mCaptionTextView.setText(mUserCaptions.get(position));

    holder.mWatcher.setActive(false);
    holder.mDetailEditText.setText(mUserDetails.get(position),BufferType.EDITABLE);
    holder.mWatcher.setPosition(position);
    holder.mWatcher.setActive(true);

    return convertView;
}

static class ViewHolder{
    public TextView mCaptionTextView;
    public EditText mDetailEditText;
    public MutableWatcher mWatcher;
}

class MutableWatcher implements TextWatcher {

    private int mPosition;
    private boolean mActive;

    void setPosition(int position) {
        mPosition = position;
    }

    void setActive(boolean active) {
        mActive = active;
    }

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

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

    @Override
    public void afterTextChanged(Editable s) {
        if (mActive) {
            mUserDetails.set(mPosition, s.toString());
        }
    }
}

希望这能帮到你。


3

检查索引值是否与您正在操作的行位置匹配。如果使用holder模式,该值可能不会从0更改为7-8,具体取决于您的屏幕大小。我曾经遇到过这样的情况,我认为我通过实现getCount方法解决了这个问题。这样,第50行给我提供了50的位置,而不是7(例如)。


我已经实现了getCount。它返回数据的大小,所以应该没问题。 - Andy Stampor
哦,我明白了。我认为问题可能是你在 onFocusChange 函数中设置的索引值。每当你设置 EditText 的值时,请尝试使用 setTag 方法同时设置其索引。然后在 onFocusChange 方法内部使用 getTag 方法进行恢复。 - zozelfelfo
啊,好的,将索引添加到EditText本身就解决了整个问题。谢谢。 - Andy Stampor

0

我曾经遇到过同样的问题,当我将滚动条移动到我的列表上/下时,我的EditText文本值会改变,然后我的解决方法是在我的EditText中添加一个setOnFocusChangeListener,并在其中添加一个addTextChangedListener,但与同一个EditText的其他实例有关。

EditText etSumScans;

@NonNull
@Override
public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
         view = convertView;

        if (view == null)
            view = LayoutInflater.from(myContextItem).inflate(resourceLayoutItem, null);

        shipmentLinesDTO = myListItem.get(position);

        etSumScans = view.findViewById(R.id.etSumScans);
        etSumScans.setText(shipmentLinesDTO.getAttribute1() );

        etSumScans.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus){
                    EditText secondInstanceEditText= v.findViewById(R.id.etSumScans);
                    secondInstanceEditText.addTextChangedListener(new TextWatcher() {
                        @Override
                        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                        }

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

                        }

                        @Override
                        public void afterTextChanged(Editable s) {
                            getItem(position).setAttribute1(s.toString());
                        }
                    });
                }
            }
        });
    }

通过这个,我解决了我的问题。 希望能帮到你。


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