问题
So, I have a custom adapter with two EditText fields on every row.
I've gotten most of the stuff working properly, except saving the values inside the 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:
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.
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:
My getView method (lots of other irrelevant code for this issue in here):
@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
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:
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());
}
}
回答1:
This can be done via careful use of 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.
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
:
<?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 answer for discussion of that problem.
回答2:
We can save value with the help of TextWatcher
Better to use A Model to store and retrieve the value of EditText.
public class RowData {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Next is TextWatcher Listener
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)
Try like this, Hope this will help you.
来源:https://stackoverflow.com/questions/19666752/edittext-in-a-list-adapter-how-to-save-the-value