Java 在列表适配器中,如何保存值?
因此,我有一个自定义适配器,每行有两个EditText字段 除了将值保存在ArrayList中之外,我已经使大部分内容正常工作 这是我到目前为止所做的代码:Java 在列表适配器中,如何保存值?,java,android,listview,android-arrayadapter,Java,Android,Listview,Android Arrayadapter,因此,我有一个自定义适配器,每行有两个EditText字段 除了将值保存在ArrayList中之外,我已经使大部分内容正常工作 这是我到目前为止所做的代码: private void holderTitleSavedOnScroll(final int position, IZUICartViewHolder holder) { if (!(position == (variantArrayList.size() - 1)) && holder.title != null
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());
}
});
}
}
所以这实际上是我想要的,它在焦点改变时保存了值。除了一个问题,它只在焦点改变时保存值
这在大多数情况下都很好,除非用户实际按下一个按钮,整个视图都消失了。焦点从未改变,值也未设置
所以我猜你们都在想,是的,让我们调用AddContextChangedListener并附加一个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);
}
不,那也不行。
当然,它确实保存了值,但是当您滚动时,它也会弄乱内容,因为listview重用了单元格,它认为一个单元格的值在另一个单元格中,然后从ArrayList设置值
我尝试过不同的方法,比如在改变值和内容时检查焦点,但它不起作用(原因或多或少很明显)
有没有创造性的解决方案
更新(包含更多代码):
建议的TextWatcher方法:
我的getView方法(这里有很多与此问题无关的代码):
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());
}
}
我们可以借助
TextWatcher
最好使用模型来存储和检索EditText的值。
public class RowData {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
接下来是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) {
}
}
您的适配器类
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
/////
}
}
公共类YourAdapter扩展了ArrayAdapter{
私有数组列表数据;
私人语境;
公共YourAdapter(上下文、ArrayList数据){
super(上下文,0,数据);
这个数据=数据;
}
@凌驾
公共视图getView(最终整数位置、视图转换视图、视图组父视图){
视图v=转换视图;
最终行数据行=data.get(位置);
最终编辑文本编辑文本=(编辑文本)v.findViewById(R.id.EditText);
如果(edittext!=null)
edittext.setText(row.getValue());
addTextChangedListener(新的EditTextWatcher(行));
///////你的代码
/////
}
}
//
edittext.addTextChangedListener(新的EditTextWatcher(行))代码>此行将存储
每个EditText的数据,即使在创建单元格时滚动ListView
它将根据模型(RowData)设置值
像这样试试,希望这会对你有所帮助。这可以通过仔细使用文本观察者来实现
在ViewHolder中包含对当前TextWatcher的引用。回收视图时,删除现有的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;
}
}
}
已知错误:当键盘打开时,EditText将失去初始焦点,有关该问题的讨论,请参阅。是否删除任何现有的TextWatcher?尝试过该操作后,无效。我无法使其正常工作,滚动期间值会出错。每次重新使用新行时,都会触发文本监视程序PostTextChanged。有什么想法吗?@JoakimEngstrom你试过我的方法吗?或者共享完整的适配器类,或者更新问题本身?使用您的方法更新问题。还尝试了一些修改,但仍然会使用重用的值设置这些值,因为每次操作系统重用一行时都会触发afterTextChanged。
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;
}
}
}
<?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>