Java 列表适配器中的 EditText,如何保存值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19666752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
EditText in a List Adapter, how to save the value?
提问by Joakim Engstrom
So, I have a custom adapter with two EditText fields on every row.
所以,我有一个自定义适配器,每行有两个 EditText 字段。
I've gotten most of the stuff working properly, except saving the values inside the ArrayList.
除了将值保存在 ArrayList 中之外,我已经让大部分内容正常工作。
This is the code I've done so far:
这是我到目前为止所做的代码:
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());
}
});
}
}
So this actually does what I want, it saves the value when the focus has changed. Except for one problem, it only saves the value when the focus has changed.
所以这实际上做了我想要的,它在焦点改变时保存值。除了一个问题,它只在焦点改变时保存值。
Which is great most of the time, except when a user actually presses a button that makes the whole view disappear. The focus never changed, and the value does not get set.
大多数情况下这很好,除非用户实际按下按钮使整个视图消失。焦点从未改变,并且值未设置。
So I'm guessing you are all thinking, yeah let's just call addOnTextChangedListener and attach a TextWatcher, by adding something like this:
所以我猜你们都在想,是的,让我们通过添加如下内容来调用 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);
}
Nope, that won't work either. Sure it actually saves the value, but it also messes stuff up when you scroll since the listview reuses the cell it thinks it the value from one cell is in the other cell and then sets the value from the ArrayList.
不,那也行不通。当然它实际上保存了值,但是当你滚动时它也会把东西弄乱,因为列表视图重用了它认为一个单元格中的值在另一个单元格中的单元格,然后设置了 ArrayList 中的值。
I've tried different things like checking focus when changing values and stuff, but it does not work (for more or less obvious reasons).
我尝试了不同的事情,比如在更改值和内容时检查焦点,但它不起作用(或多或少有明显的原因)。
Is there any creative solutions to solve this?
是否有任何创造性的解决方案来解决这个问题?
UPDATE (With more code):
更新(更多代码):
The TextWatcher approach as suggested:
建议的 TextWatcher 方法:
My getView method (lots of other irrelevant code for this issue in here):
我的 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;
}
The holderTitleSavedOnScroll method
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)));
}
}
The TextWatcher class:
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());
}
}
采纳答案by blahdiblah
This can be done via careful use of TextWatchers.
这可以通过仔细使用 TextWatchers 来完成。
Include a reference to the current TextWatcher in your ViewHolder. When a view is recycled, remove the existing TextWatcher and add a new one, keyed to the current position.
在您的 ViewHolder 中包含对当前 TextWatcher 的引用。当一个视图被回收时,移除现有的 TextWatcher 并添加一个新的,锁定到当前位置。
Here is a complete working example, including state saving to allow testing navigating away:
这是一个完整的工作示例,包括状态保存以允许测试导航:
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
:
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>
Known bug: an EditText will lose initial focus when the keyboard comes up, see this answerfor discussion of that problem.
已知错误:当键盘出现时 EditText 将失去初始焦点,请参阅此答案以讨论该问题。
回答by Amit Gupta
We can save value with the help of TextWatcher
我们可以在以下帮助下节省价值 TextWatcher
Better to use A Model to store and retrieve the value of EditText.
最好使用 A Model 来存储和检索 EditText 的值。
public class RowData {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Next is TextWatcher Listener
接下来是 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) {
}
}
Your Adapter Class
你的适配器类
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));
This line will store
the data for each EditText, and even if you will scroll the ListView then while creating cell
it will set the value from Model(RowData)
//
edittext.addTextChangedListener(new EditTextWatcher(row));
此行将存储每个 EditText 的数据,即使您将滚动 ListView 然后在创建单元格时它也会从 Model(RowData) 设置值
Try like this, Hope this will help you.
试试这个,希望这会帮助你。