带有 edittext 和 textwatcher 的列表视图。 Textwatcher 触发多次(超过 3 次)
Listview with edittext and textwatcher. Textwatcher fires multiple times (more than 3 times)
我有一个自定义列表适配器,其中一个列表项具有三个编辑文本。我有一个日期选择器供其中之一使用。设置日期后,适配器的相应型号会正确保存日期。但是对于其他编辑文本,我只想将输入的文本存储在列表中。我使用 textwatcher 来完成任务。我的问题是文本观察器针对视图中的单个条目多次触发(准确地说是 5 次)。
如果其中一个编辑文本工作正常,为什么另一个不能?我真的需要一些帮助。到目前为止,我一直无法找到任何成功。
public class AddExpensesAdapter extends BaseAdapter{
private Activity activity;
private ArrayList<AddExpensesModel> addExpensesList;
private LayoutInflater inflater;
private TextView totalAmount;
private ArrayList<String> array_amount= new ArrayList<String>();
private ArrayList<String> array_name= new ArrayList<String>();
public AddExpensesAdapter(Activity activity, ArrayList<AddExpensesModel> addExpensesList) {
this.activity = activity;
this.addExpensesList = addExpensesList;
this.inflater = (LayoutInflater) this.activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return addExpensesList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
public AddExpensesModel getExpenseModel(int position)
{
return addExpensesList.get(position);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.a_add_expenses_listitem, null);
viewHolder.expenseName = (EditText) convertView.findViewById(R.id.add_expenses_et_expense_name);
viewHolder.dateTime = (EditText) convertView.findViewById(R.id.add_expenses_et_date_time);
viewHolder.amount = (EditText) convertView.findViewById(R.id.add_expenses_et_amount);
viewHolder.editDate = (ImageView) convertView.findViewById(R.id.add_expenses_edit_date);
viewHolder.number = (TextView) convertView.findViewById(R.id.add_expenses_tv_serial_number);
viewHolder.deleteExpense = (ImageView) convertView.findViewById(R.id.add_expenses_delete_expense);
// viewHolder.totalfriends = (TextView)
// convertView.findViewById(R.id.eventtotalfriends);
convertView.setTag(viewHolder);
viewHolder.ref = position;
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final AddExpensesModel addExpenseModel = addExpensesList.get(position);
viewHolder.expenseName.setText(addExpenseModel.getExpenseName());
viewHolder.dateTime.setText(addExpenseModel.getDateTime());
viewHolder.amount.setText(addExpenseModel.getAmount());
viewHolder.number.setText(""+(position+1)+".");
viewHolder.editDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
setDate(addExpenseModel);
} catch (Exception e) {
e.printStackTrace();
}
}
});
viewHolder.deleteExpense.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
addExpensesList.remove(position);
notifyDataSetChanged();
}
});
viewHolder.amount.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void afterTextChanged(Editable editable) {
if(!editable.toString().equals(""))
{
addExpenseModel.setAmount(editable.toString());
}
notifyDataSetChanged();
}
});
return convertView;
}
public void setDate(final AddExpensesModel model) throws Exception {
final String dateFormatPattern = "MMM, dd yyyy";
final SimpleDateFormat sdf = new SimpleDateFormat(dateFormatPattern,
Locale.getDefault());
DatePickerDialog.OnDateSetListener date = new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, monthOfYear);
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
model.setDateTime(sdf.format(cal.getTime()));
notifyDataSetChanged();
}
};
Calendar cal = Calendar.getInstance();
cal.setTime(sdf.parse(model.getDateTime()));
new DatePickerDialog(this.activity, date, cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)).show();
}
static class ViewHolder {
EditText expenseName;
EditText dateTime;
EditText amount;
ImageView editDate;
ImageView deleteExpense;
TextView number;
}
}
因为你的Edit Text上有Text Watcher,每次你输入字符时,text watcher都会被调用,每次你的notifyDataSetChanged()都会被撤销。
例如:假设您要保存金额453,它将被触发3次。
我知道我来晚了,但我会把它留给未来的读者。将 textwatchers
设置为 listview
项目有点棘手,因为它们的回收性质以及 Textwatchers
被添加到编辑文本而不是被替换。因此,每次创建行视图或绑定到新数据时,您都需要删除不正确的并添加新的观察者。尝试以下实施:
自定义文本观察器。 (对象项是包含您的行数据的对象)
私有 class CustomWatcher 实现 TextWatcher
{
私有对象项;
private CustomWatcher(Object item)
{
this.item = item;
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
@Override
public void afterTextChanged(Editable editable)
{
}
}
将 textwatcher
添加到 edittext
并删除前一个,在 getView()
函数中。
CustomWatcher oldWatcher = (CustomWatcher)holder.editDate.getTag();
如果(旧观察者!= null)
holder.editDate.removeTextChangedListener(旧观察者);
//在此处使用模型数据填充您的 editText(在添加新的文本观察器之前)
CustomWatcher newWatcher = new CustomWatcher(rowItem);
holder.editDate.setTag(newWatcher);
holder.editDate.addTextChangedListener(newWatcher);
完成。您现在可以将文本保存在相应的行数据对象中。这样,您的 Textwatchers 将在它们不再有用时被删除,并防止内存泄漏。
我试图解决我的一个问题,当 listview
的 edittext
有 textWatcher
.
时无法获得位置
这是对我有用的解决方案:
里面getview()
当我向 editText
添加 textWatcher
侦听器时,我还添加了以下行:
edittext.setTag(R.id.position<any unique string identitiy>, position);
在你的 afterTextChanged()
中:
int position = edittext.getTag(R.id.position);
它给出了正确的位置,您可以根据位置进行修改。
在 Kotlin 中,您可以使用以下扩展方法解决此问题。
fun EditText.onChange(cb: (str: String) -> Unit){
this.removeWatcher()
val watcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
cb(s.toString())
}
}
this.addTextChangedListener(watcher)
this.tag = watcher
}
fun EditText.removeWatcher() {
if(this.tag as TextWatcher? != null) {
this.removeTextChangedListener(this.tag as TextWatcher)
}
}
像
一样从适配器使用它
yourEditText.onChange { str -> // str is the new content
// TODO: Implement listener here
}
只要您需要从 EditText
.
中删除所有观察者,就可以使用 removeWatcher
方法
例如:如果您使用 setText
从适配器在 EditText 中设置一些文本,将调用已添加的观察器。在这种情况下,如果您在 setText
之前删除所有现有观察者,则可以避免不必要的观察者调用
我有一个自定义列表适配器,其中一个列表项具有三个编辑文本。我有一个日期选择器供其中之一使用。设置日期后,适配器的相应型号会正确保存日期。但是对于其他编辑文本,我只想将输入的文本存储在列表中。我使用 textwatcher 来完成任务。我的问题是文本观察器针对视图中的单个条目多次触发(准确地说是 5 次)。
如果其中一个编辑文本工作正常,为什么另一个不能?我真的需要一些帮助。到目前为止,我一直无法找到任何成功。
public class AddExpensesAdapter extends BaseAdapter{
private Activity activity;
private ArrayList<AddExpensesModel> addExpensesList;
private LayoutInflater inflater;
private TextView totalAmount;
private ArrayList<String> array_amount= new ArrayList<String>();
private ArrayList<String> array_name= new ArrayList<String>();
public AddExpensesAdapter(Activity activity, ArrayList<AddExpensesModel> addExpensesList) {
this.activity = activity;
this.addExpensesList = addExpensesList;
this.inflater = (LayoutInflater) this.activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return addExpensesList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
public AddExpensesModel getExpenseModel(int position)
{
return addExpensesList.get(position);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.a_add_expenses_listitem, null);
viewHolder.expenseName = (EditText) convertView.findViewById(R.id.add_expenses_et_expense_name);
viewHolder.dateTime = (EditText) convertView.findViewById(R.id.add_expenses_et_date_time);
viewHolder.amount = (EditText) convertView.findViewById(R.id.add_expenses_et_amount);
viewHolder.editDate = (ImageView) convertView.findViewById(R.id.add_expenses_edit_date);
viewHolder.number = (TextView) convertView.findViewById(R.id.add_expenses_tv_serial_number);
viewHolder.deleteExpense = (ImageView) convertView.findViewById(R.id.add_expenses_delete_expense);
// viewHolder.totalfriends = (TextView)
// convertView.findViewById(R.id.eventtotalfriends);
convertView.setTag(viewHolder);
viewHolder.ref = position;
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final AddExpensesModel addExpenseModel = addExpensesList.get(position);
viewHolder.expenseName.setText(addExpenseModel.getExpenseName());
viewHolder.dateTime.setText(addExpenseModel.getDateTime());
viewHolder.amount.setText(addExpenseModel.getAmount());
viewHolder.number.setText(""+(position+1)+".");
viewHolder.editDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
setDate(addExpenseModel);
} catch (Exception e) {
e.printStackTrace();
}
}
});
viewHolder.deleteExpense.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
addExpensesList.remove(position);
notifyDataSetChanged();
}
});
viewHolder.amount.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void afterTextChanged(Editable editable) {
if(!editable.toString().equals(""))
{
addExpenseModel.setAmount(editable.toString());
}
notifyDataSetChanged();
}
});
return convertView;
}
public void setDate(final AddExpensesModel model) throws Exception {
final String dateFormatPattern = "MMM, dd yyyy";
final SimpleDateFormat sdf = new SimpleDateFormat(dateFormatPattern,
Locale.getDefault());
DatePickerDialog.OnDateSetListener date = new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, monthOfYear);
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
model.setDateTime(sdf.format(cal.getTime()));
notifyDataSetChanged();
}
};
Calendar cal = Calendar.getInstance();
cal.setTime(sdf.parse(model.getDateTime()));
new DatePickerDialog(this.activity, date, cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)).show();
}
static class ViewHolder {
EditText expenseName;
EditText dateTime;
EditText amount;
ImageView editDate;
ImageView deleteExpense;
TextView number;
}
}
因为你的Edit Text上有Text Watcher,每次你输入字符时,text watcher都会被调用,每次你的notifyDataSetChanged()都会被撤销。
例如:假设您要保存金额453,它将被触发3次。
我知道我来晚了,但我会把它留给未来的读者。将 textwatchers
设置为 listview
项目有点棘手,因为它们的回收性质以及 Textwatchers
被添加到编辑文本而不是被替换。因此,每次创建行视图或绑定到新数据时,您都需要删除不正确的并添加新的观察者。尝试以下实施:
自定义文本观察器。 (对象项是包含您的行数据的对象)
私有 class CustomWatcher 实现 TextWatcher { 私有对象项;
private CustomWatcher(Object item) { this.item = item; } @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void afterTextChanged(Editable editable) { }
}
将
textwatcher
添加到edittext
并删除前一个,在getView()
函数中。CustomWatcher oldWatcher = (CustomWatcher)holder.editDate.getTag(); 如果(旧观察者!= null) holder.editDate.removeTextChangedListener(旧观察者);
//在此处使用模型数据填充您的 editText(在添加新的文本观察器之前)
CustomWatcher newWatcher = new CustomWatcher(rowItem); holder.editDate.setTag(newWatcher); holder.editDate.addTextChangedListener(newWatcher);
完成。您现在可以将文本保存在相应的行数据对象中。这样,您的 Textwatchers 将在它们不再有用时被删除,并防止内存泄漏。
我试图解决我的一个问题,当 listview
的 edittext
有 textWatcher
.
这是对我有用的解决方案:
里面getview()
当我向 editText
添加 textWatcher
侦听器时,我还添加了以下行:
edittext.setTag(R.id.position<any unique string identitiy>, position);
在你的 afterTextChanged()
中:
int position = edittext.getTag(R.id.position);
它给出了正确的位置,您可以根据位置进行修改。
在 Kotlin 中,您可以使用以下扩展方法解决此问题。
fun EditText.onChange(cb: (str: String) -> Unit){
this.removeWatcher()
val watcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
cb(s.toString())
}
}
this.addTextChangedListener(watcher)
this.tag = watcher
}
fun EditText.removeWatcher() {
if(this.tag as TextWatcher? != null) {
this.removeTextChangedListener(this.tag as TextWatcher)
}
}
像
一样从适配器使用它yourEditText.onChange { str -> // str is the new content
// TODO: Implement listener here
}
只要您需要从 EditText
.
removeWatcher
方法
例如:如果您使用 setText
从适配器在 EditText 中设置一些文本,将调用已添加的观察器。在这种情况下,如果您在 setText
之前删除所有现有观察者,则可以避免不必要的观察者调用