6

所以,我有一个自定义适配器,每行都有两个 EditText 字段。

除了将值保存在 ArrayList 中之外,我已经让大多数东西正常工作。

这是我到目前为止所做的代码:

private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) {
    if (!(position == (variantArrayList.size() - 1)) && holder.title != null) {
        holder.title.setText(variantArrayList.get(position).getVariantTitle());
        final int finalPosition = position;
        holder.title.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                    final EditText newVariant = (EditText) v;
                    variantArrayList.get(finalPosition).setVariantTitle(newVariant.getText().toString());
            }
        });
    }
}

所以这实际上做了我想要的,它在焦点改变时保存了值。除了一个问题,它只在焦点改变时保存值。

这在大多数情况下都很棒,除非用户实际按下按钮使整个视图消失。焦点从未改变,值也未设置。

所以我猜你们都在想,是的,我们只需调用 addOnTextChangedListener 并附加一个 TextWatcher,通过添加如下内容:

        holder.title.setText(variantArrayList.get(position).getVariantTitle());
        final int finalPosition = position;
        final EditText holderTitle = (EditText) holder.title;

        if (holderTitle.getTag() != null) {
            final TextWatcher textWatcher = 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) {
                        variantArrayList.get(finalPosition).setVariantTitle(s.toString());
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            };


            holder.title.addTextChangedListener(textWatcher);
            holder.title.setTag(true);
        }

不,那也行不通。当然它实际上保存了值,但是当你滚动时它也会弄乱东西,因为列表视图重用了它认为它认为来自一个单元格的值在另一个单元格中的单元格,然后设置来自 ArrayList 的值。

我尝试了不同的方法,例如在更改值和内容时检查焦点,但它不起作用(出于或多或少明显的原因)。

有没有创造性的解决方案来解决这个问题?

更新(使用更多代码):

建议的 TextWatcher 方法:

我的 getView 方法(这里有很多其他与此问题无关的代码):

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    IZUICartViewHolder holder;
    LayoutInflater inflater = ((Activity) context).getLayoutInflater();

    if (v == null) {

        holder = new IZUICartViewHolder();
        int type = getItemViewType(position);

        switch (type) {
            case TYPE_EDIT:
                v = inflater.inflate(R.layout.iz_ui_modify_product_cell, parent, false);
                holder.title = (EditText) v.findViewById(R.id.iz_prod_modify_variant_title);
                holder.title.setHint(addVariantPlaceholder);
                holder.deleteButton = v.findViewById(R.id.click_remove);
                holder.price = (EditText) v.findViewById(R.id.iz_prod_modify_price);
                holder.price.setHint(pricePlaceholder);
                holder.price.setText(String.valueOf(0.0));
                break;

        }

        v.setTag(holder);

    } else {
        holder = (IZUICartViewHolder) v.getTag();
    }

    hideDeleteButton(holder, position);
    holderTitleSavedOnScroll(position, holder);
    holderPriceSavedOnScroll(position, holder);

    v.setTag(holder);
    return v;
}

holderTitleSavedOnScroll 方法

private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) {
    if (!(position == (variantArrayList.size() - 1)) && holder.title != null) {

        holder.title.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                v.requestFocus();
            }
        });


        final int finalPosition = position;
        final EditText holderTitle = (EditText) holder.title;

        if (holderTitle != null) {
            holder.title.setText(variantArrayList.get(position).getVariantTitle());
        }

        holderTitle.addTextChangedListener(new EditVariantTextWatcher(variantArrayList.get(finalPosition)));

    }
}

TextWatcher 类:

public class EditVariantTextWatcher implements TextWatcher {

private IZUIProductVariantContainer variantContainer;

protected EditVariantTextWatcher(IZUIProductVariantContainer variantContainer) {
    this.variantContainer = variantContainer;
}

@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) {
    variantContainer.setVariantTitle(s.toString());
}
}
4

2 回答 2

7

这可以通过仔细使用 TextWatchers 来完成。

在 ViewHolder 中包含对当前 TextWatcher 的引用。当视图被回收时,删除现有的 TextWatcher 并添加一个新的,键控到当前位置。

这是一个完整的工作示例,包括状态保存以允许测试导航:

public class EditTextListActivity extends ListActivity {

    private static final String SAVED_STATE_KEY = "saved_state_key";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        EditTextAdapter editTextAdapter = new EditTextAdapter(this, R.layout.main);
        setListAdapter(editTextAdapter);

        // Restore our state, if there is any
        if (savedInstanceState != null) {
            List<String> savedStrings = savedInstanceState.getStringArrayList(SAVED_STATE_KEY);
            for (String savedString : savedStrings)
                editTextAdapter.add(new ListItem(savedString));
        } else {
            // Add some empty items so that we can see it in action
            for (int i = 0; i < 30; i++)
                editTextAdapter.add(new ListItem(""));
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        ArrayList<String> arrayList = new ArrayList<String>();
        EditTextAdapter editTextAdapter = (EditTextAdapter) getListAdapter();
        for (int i = 0; i < editTextAdapter.getCount(); i++)
            arrayList.add(editTextAdapter.getItem(i).string1);
        outState.putStringArrayList(SAVED_STATE_KEY, arrayList);
    }

    /**
     * The object we have a list of, probably more complex in your app
     */
    static class ListItem {
        public String string1;

        ListItem(String string1) {
            this.string1 = string1;
        }
    }

    /**
     * ViewHolder which also tracks the TextWatcher for an EditText
     */
    static class ViewHolder {
        public TextView textView;
        public EditText editText;
        public TextWatcher textWatcher;
    }

    class EditTextAdapter extends ArrayAdapter<ListItem> {
        EditTextAdapter(Context context, int resource) {
            super(context, android.R.layout.simple_list_item_single_choice);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View rowView = convertView;
            if (rowView == null) {
                // Not recycled, inflate a new view
                rowView = getLayoutInflater().inflate(R.layout.main, null);
                ViewHolder viewHolder = new ViewHolder();
                viewHolder.textView = (TextView) rowView.findViewById(R.id.textview);
                viewHolder.editText = (EditText) rowView.findViewById(R.id.edittext1);
                rowView.setTag(viewHolder);
            }

            ViewHolder holder = (ViewHolder) rowView.getTag();
            // Remove any existing TextWatcher that will be keyed to the wrong ListItem
            if (holder.textWatcher != null)
                holder.editText.removeTextChangedListener(holder.textWatcher);

            final ListItem listItem = getItem(position);

            // Keep a reference to the TextWatcher so that we can remove it later
            holder.textWatcher = 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) {
                    listItem.string1 = s.toString();
                }

                @Override
                public void afterTextChanged(Editable s) {
                }
            };
            holder.editText.addTextChangedListener(holder.textWatcher);

            holder.editText.setText(listItem.string1);
            holder.textView.setText(Integer.toString(position));

            return rowView;
        }
    }
}

layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textview"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/edittext1"
        android:layout_width="0dp"
        android:layout_height="?android:attr/listPreferredItemHeightSmall"
        android:layout_weight="2"
        android:inputType="text" />

    <!-- This EditText is included to demonstrate problems with a naive approach. -->
    <EditText
        android:inputType="text"
        android:layout_width="0dp"
        android:layout_height="?android:attr/listPreferredItemHeightSmall"
        android:layout_weight="2" />
</LinearLayout>

已知错误:当键盘出现时,EditText 将失去初始焦点,请参阅此答案以讨论该问题。

于 2013-10-31T23:36:27.190 回答
0

我们可以通过以下方式节省价值TextWatcher

最好使用 A Model 来存储和检索 EditText 的值。

public class RowData {

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
} 

接下来是 TextWatcher 监听器

public class EditTextWatcher implements TextWatcher {

    private RowData data;

    public EditTextWatcher(RowData data) {
        this.data = data;
    }

    @Override
    public void afterTextChanged(Editable s) {
        data.setValue(s.toString());
    }

    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
            int arg3) {

    }

    @Override
    public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {

    }

}

你的适配器类

         public class YourAdapter extends ArrayAdapter<RowData> {
                private ArrayList<RowData> data;
                private Context context;
            public YourAdapter(Context context, ArrayList<RowData> data) {
                    super(context, 0, data);
                    this.data = data;
                }
            @Override
            public View getView(final int position, View convertView, ViewGroup parent) {
                View v = convertView;
                final RowData row = data.get(position);
                final EditText edittext = (EditText) v.findViewById(R.id.edittext);
                if (edittext != null)
                   edittext.setText(row.getValue());
                edittext.addTextChangedListener(new EditTextWatcher(row));


                ///////Your Code
                /////
        }
}

// edittext.addTextChangedListener(new EditTextWatcher(row));此行将存储每个 EditText 的数据,即使您滚动 ListView 然后在创建单元格时它也会从 Model(RowData) 中设置值

试试这样,希望这会对你有所帮助。

于 2013-10-29T19:45:41.393 回答