I have list item with EditText in it, I dont know how many items there will be. I have a problem when I enter some text in EditText, and then scroll down a ListView, after I've scroll up again there is no text in my first EditText, or there is some text from other EditText from ListView.
Code :
public class MatHangAdapter
extends ArrayAdapter<MatHangModel> {
private static final int LAYOUT_ITEM_MAP_DOWNLOAD = R.layout.item_mat_hang;
private final LayoutInflater mInflater;
Context context;
public MatHangAdapter(final Context context) {
super(context,
LAYOUT_ITEM_MAP_DOWNLOAD,
new CopyOnWriteArrayList<MatHangModel>());
this.mInflater = LayoutInflater.from(context);
this.context = context;
}
/**
* input data from outside.
*/
public void fillData(List<MatHangModel> dataModels) {
this.clear();
this.addAll(dataModels);
}
#Override
public long getItemId(final int position) {
return position;
}
#Override
public View getView(int position,
View convertView,
ViewGroup parent) {
final ViewHolder holder;
if (convertView != null) {
holder = (ViewHolder) convertView.getTag();
} else {
final View view =
this.mInflater.inflate(LAYOUT_ITEM_MAP_DOWNLOAD,
parent,
false);
holder = new ViewHolder(getContext(),
view);
view.setTag(holder);
convertView = view;
}
//fill data.
holder.fillData(this.getItem(position));
return convertView;
}
public static class ViewHolder {
private final Context mContext;
// Fields.
#InjectView(R.id.tv_scan_barcode)
TextView tvScanBarcode;
#InjectView(R.id.tv_qty_price)
TextView tvQtyPrice;
#InjectView(R.id.et_amount)
EditText etAmount;
public ViewHolder(Context context,
View view) {
ButterKnife.inject(this,
view);// Initialize UI controls.
mContext = context;
//apply fonts....
// CommonUtil.setFontForMainTitleTopicViewRecursive(tvItemMenu);
}
/**
* fill data.
*/
public void fillData(MatHangModel matHangModel) {
//fill data
if (matHangModel != null) {
tvScanBarcode.setText(CommonUtil.getStringData(matHangModel.getBracode()));
tvQtyPrice.setText(""+CommonUtil.getIntegerData(matHangModel.getPrice()));
etAmount.setText(""+CommonUtil.getIntegerData(matHangModel.getAmount()));
etAmount.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(final CharSequence charSequence,
int start,
int before, int count) {
}
#Override
public void onTextChanged(final CharSequence charSequence,
final int i,
final int i1,
final int i2) {
}
#Override
public void afterTextChanged(final Editable editable) {
}
});
}
}
#OnClick(R.id.tv_scan_barcode)
void onSceanBarcode(View view){
CommonUtil.showViewWithAnimation(Techniques.FadeIn,view);
}
}
}
It's happen because of the ListView recycling mechanism, you need to update your Adapter data with the new value of the EditTexts.
For better performance, you can do it inside afterTextChanged() of the TextWatcher( to update the data only when you finish editing the text):
#Override
public void afterTextChanged(final Editable editable) {
// update your model
// matHangModel.setAmount(Integer.parseInt(editable.toString()));
// update your adapter data with the new value of "matHangModel"
}
EDIT
1) Add an update method in your adapter:
public void updateItem(MatHangModel model, int position){
this.insert(model, position);
}
2) Change your fillData method to pass to position as param, because you'll need it in the update:
public void fillData(MatHangModel matHangModel, int position) {
//fill data
if (matHangModel != null) {
tvScanBarcode.setText(CommonUtil.getStringData(matHangModel.getBracode()));
tvQtyPrice.setText(""+CommonUtil.getIntegerData(matHangModel.getPrice()));
etAmount.setText(""+CommonUtil.getIntegerData(matHangModel.getAmount()));
etAmount.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(final CharSequence charSequence,
int start,
int before, int count) {
}
#Override
public void onTextChanged(final CharSequence charSequence,
final int i,
final int i1,
final int i2) {
}
#Override
public void afterTextChanged(final Editable editable) {
matHangModel.setAmount(Integer.parseInt(editable.toString())); // here you update your model data
updateItem(matHangModel, position); // here you update your adapter data
}
});
}
}
As you know, Android recycle the views in a ListView so the text you entered in the EditText may be lost if you don't store it.
In the onTextChanged method of the TextWatcher store the text you entered with something like matHangModel.setAmount(etAmount.getText().toString())
Try this:
#Override
public void onTextChanged(final CharSequence charSequence,
final int i,
final int i1,
final int i2) {
matHangModel.setAmount(charSequence.toString()); //if amount is int then parse value. In layout EditText set android:inputType="number"
android:ems="10"
}
Related
I want to add some new rows to a custom listview by clicking a button. My every row contains an EditText. My need is to create new rows while clicking on the Button each time. I made it successfully, but the problem am facing here is, while am clicking the Button, a new row will be created but it's refreshing the whole custom listview and it's replace everything that I wrote in EditText with empty (it's creating some new EditText). I don't need to happen that. I need to preserve the whole data what I wrote in the EditText even after a new row is created.
Here is my code with calls the adapter:
final RequestAttributeAdapter adapter = new RequestAttributeAdapter(context,listItems);
lv_Attribute.setAdapter(adapter);
tvAddAttribute.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listItems.add("1");
adapter.notifyDataSetChanged();
}
});
Here is my adapter class:
private ArrayList<String> attributes;
private LayoutInflater inflater;
public RequestAttributeAdapter(Context context, ArrayList<String> attributes) {
this.attributes = attributes;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return attributes.size();
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#SuppressLint({"InflateParams", "ViewHolder"})
#Override
public View getView(final int position, View view, ViewGroup viewGroup) {
view = inflater.inflate(R.layout.item_attribute_list,null);
FloatingEditText ftName = (FloatingEditText) view.findViewById(R.id.etAttrName);
TextView attributeNumber = (TextView) view.findViewById(R.id.attributeNumber);
attributeNumber.setText("Attribute : "+(position+1));
//CheckBox cbRequired = (CheckBox) view.findViewById(R.id.cbRequired);
//cbRequired.setChecked(attributes.get(position).isRequired());
//ftName.setText(attributes.get(position).getAttribute_name());
if (position>0)
ftName.requestFocus();
ftName.addTextChangedListener(new TextWatcher() {
#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) {
//attributes.get(position).setAttribute_name(editable.toString());
}
});
return view;
}
I think it is impossible by using notifyDataSetChanged() function, but you can try this https://android.jlelse.eu/smart-way-to-update-recyclerview-using-diffutil-345941a160e0
You can achieve this By saving data of EditText into ArrayList according to their positions and in getView() get data from ArrayList and setText() to EditText
Hope this will help
I'm creating an android app, in which I'm using recyclerView and the row of recyclerView is having editText.
This is my ReadingAdapter class
public class ReadingAdapter extends RecyclerView.Adapter<ReadingAdapter.ViewHolder> implements AdapterView.OnItemSelectedListener {
Context context;
String valOpenReading, valClosReading, valConsumption;
private List<ReadingData> readingList;
static String[] arrValOpenRead, arrValClosRead, arrValConsumption;
public ReadingAdapter(Context context, List<ReadingData> readingList) {
this.context = context;
this.readingList = readingList;
arrValOpenRead = new String[readingList.size()];
arrValClosRead = new String[readingList.size()];
arrValConsumption = new String[readingList.size()];
}
#Override
public ReadingAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.reading_sheet_layout, parent, false);
return new ReadingAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(final ReadingAdapter.ViewHolder holder, final int position) {
ReadingData tempData = readingList.get(position);
holder.pdtName.setText(tempData.pdtName);
holder.keyId.setText("Key "+tempData.keyId);
holder.etClosRead.addTextChangedListener(new TextWatcher() {
boolean ignore = false;
#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) {
if (ignore)
return;
ignore = true;
valOpenReading = holder.etOpenRead.getText().toString();
arrValOpenRead[position] = valOpenReading;
valClosReading = s.toString().equals("") ? "0": s.toString();
arrValClosRead[position] = valClosReading;
if (!valOpenReading.equals("")) {
if (Integer.parseInt(valClosReading) < Integer.parseInt(valOpenReading)) {
Toast.makeText(context, "Check once! closing reading should be more than opening reading!", Toast.LENGTH_LONG).show();
valConsumption = "0";
holder.consumption.setText("");
} else {
valConsumption = (Integer.parseInt(valClosReading) - Integer.parseInt(valOpenReading))+"";
arrValConsumption[position] = valConsumption;
holder.consumption.setText(valConsumption);
}
} else
Toast.makeText(context, "Please fill the opening reading!", Toast.LENGTH_SHORT).show();
ignore = false;
}
});
}
#Override
public int getItemCount() {
return readingList.size();
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView pdtName, keyId, consumption;
EditText etOpenRead, etClosRead;
public ViewHolder(View view) {
super(view);
pdtName = (TextView)view.findViewById(R.id.txt_list_pdt_supp);
keyId = (TextView)view.findViewById(R.id.key_set);
etOpenRead = (EditText)view.findViewById(R.id.open_val_set);
etClosRead = (EditText)view.findViewById(R.id.clos_val_set);
consumption = (TextView)view.findViewById(R.id.consumption_val);
}
}
}
This is my ReadingData.java
public class ReadingData {
String pdtName, keyId, openReading, closReading, consumption;
public ReadingData(String pdtName, String keyId) {
this.pdtName = pdtName;
this.keyId = keyId;
}
}
Here, if I enter value in the starting items of the recyclerView then as I scroll up the items to the bottom of the list, the last item will have that value.
Please ignore the quality of image as we can't upload above of 2MiB of snap.
Here the views are recycled as the list is scrolled. How to prevent the copying values to the other item in the list.
And that Toast is also repeated several times. How to stop this.
update:
By the suggetion of LQ Gioan through the SO question How ListView's recycling mechanism works , I got the logic how ListView actually works with recycling of views.
But I'm not sure whether the recyclerView also works same.
But here in my case, how can I implement this process. pls someone help me here.
RecyclerView reuse views, in fact it only generate the as many as views that is visible on the screen. so it's expected if you can see a value you set for other rows
The solution would be set all attributes of the view that you are changing to default or whatever the row should present from your data set
So put addTextChangedListener insode ViewHolder constructor(you can get position by calling getAdapterPosition()) for better performance and set the editText value inside onBindViewHolder method from your data set
Your Activity Code:
ListView listview = (ListView) findViewById(R.id.list_view);
listview.setItemsCanFocus(true);
Adapter adapter = new Adapter (YourActivity.this, YourArrayList);
listview .setAdapter(adapter);
Adapter class
public class Adapter extends BaseAdapter {
// Declare Variables \\
Context mContext;
LayoutInflater inflater;
Activity act;
String[] temp;
public Adapter(Context context, ArrayList<String> list) {
mContext = context;
inflater = LayoutInflater.from(mContext);
act = (Activity) context;
//-------Temp String Array-------\\
temp = new String[this.count];
for (int i = 0; i < this.count; i++) {
temp[i] = list.get(i);
}
//---------------------------\\
}
public class ViewHolder {
TextView optionTitle;
EditText optionText;
int ref;
}
#Override
public int getCount() {
return list.size;
}
#Override
public Object getItem(int position) {
return temp[position];
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(final int position, View view, ViewGroup parent) {
final ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = inflater.inflate(R.layout.lv_items_add_ques_options_mcq, null);
holder.optionTitle = (TextView) view.findViewById(R.id.add_ques_opts_count_mcq_tv);
holder.optionText = (EditText) view.findViewById(R.id.add_ques_opts_title_mcq_et);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.ref = position;
holder.optionTitle.setText(getCharForNumber(position) + ":");
holder.optionText.setText(temp[position]);
holder.optionText.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}
#Override
public void afterTextChanged(Editable arg0) {
temp[holder.ref] = arg0.toString().trim();
}
});
return view;
}
public void getList() {
StaticValues.arrayListOptions = new ArrayList<String>(Arrays.asList(temp));
StaticValues.arrayListOptionsCount = new ArrayList<String>();
for (int i = 0; i < count; i++) {
StaticValues.arrayListOptionsCount.add(String.valueOf(i+1));
Log.e("err_al", StaticValues.arrayListOptions.get(i));
Log.e("err_al", StaticValues.arrayListOptionsCount.get(i));
}
}
private String getCharForNumber(int i) {
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
if (i > 25) {
return null;
}
return Character.toString(alphabet[i]);
}}
I have a listview consists of TextView, EditText and Checkbox. I am want to make the state of the edittext to be persistent so that, when i change the text
inside the edittext and then scroll the listview up or down that text that was added/written into the edittext should not be changed and must remain as it is
I managed to make the checkbox persistent, I do not know how to make the edittext state persistent.
please have a look at the getView() methos it is posted below
and please let me know how to solve this issue
getView
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = null;
if (convertView == null) {
LayoutInflater layoutinflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
view = layoutinflater.inflate(R.layout.model, null);
final ViewHolder holder = new ViewHolder();
holder.tv = (TextView) view.findViewById(R.id.tv);
holder.cb = (CheckBox) view.findViewById(R.id.cb);
holder.et = (EditText) view.findViewById(R.id.et);
holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
ItemDesign element = (ItemDesign) holder.cb.getTag();
element.setChecked(buttonView.isChecked());
}
});
view.setTag(holder);
holder.cb.setTag(designList.get(position));//checkbox
//edittext
ItemDesign element = (ItemDesign) holder.et.getTag();
if (element != null) {
element.setEtTxt(holder.et.getText().toString());
}
holder.et.setTag(designList.get(position));
holder.tv.setTag(designList.get(position));//textview
} else {
view = convertView;
((ViewHolder)view.getTag()).et.setTag(designList.get(position));//edittext
((ViewHolder)view.getTag()).tv.setTag(designList.get(position));//textview
((ViewHolder)view.getTag()).cb.setTag(designList.get(position));//checkbox
}
ViewHolder holder = (ViewHolder) view.getTag();
holder.tv.setText(designList.get(position).getTxt()); //textview
holder.cb.setChecked(designList.get(position).isChecked());//checkbox
//edittext
String etTxt = holder.et.getText().toString();
designList.get(position).setEtTxt(etTxt);
holder.et.setText(designList.get(position).getEtTxt());
return view;
}
private class ViewHolder {
TextView tv;
CheckBox cb;
EditText et;
}
You should add a TextWatcher to your edit text and use that to track the text inputted to the textview.
holder.et.setTag(designList.get(position));//edittext
holder.et.addTextChangedListener(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) {
}
#Override
public void afterTextChanged(Editable s) {
ItemDesign element = (ItemDesign) holder.cb.getTag();
element.setEditTextValue(s.toString())
}
if I understood you correctly, you need to register TextWatcher in your EditText and save string value every time, when you change text in it. So you will need to update you part of code from:
String etTxt = holder.et.getText().toString();
designList.get(position).setEtTxt(etTxt);
holder.et.setText(designList.get(position).getEtTxt());
to (sorry, I don't know what time of element do you have in designList, but let it be, for example, type Item, you can past your type instead of it):
final Item designItem = designList.get(position);
holder.et.setText(designItem.getEtTxt());
holder.et.addTextChangedListener(new TextWatcher() {
#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) {
designItem.setEtTxt(editable.toString);
}
});
But be careful. This solution is not working yet, since you have register new and new watchers but don't clear old. There is no perfect solution in this situation for me, since EditText doesn't have something like clearTextChangedListeners(). But you can solve it with introducing your own EditText (copied from here):
public class ExtendedEditText extends EditText {
private ArrayList<TextWatcher> mListeners = null;
public ExtendedEditText(Context ctx) {
super(ctx);
}
public ExtendedEditText(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
}
public ExtendedEditText(Context ctx, AttributeSet attrs, int defStyle) {
super(ctx, attrs, defStyle);
}
#Override
public void addTextChangedListener(TextWatcher watcher) {
if (mListeners == null) {
mListeners = new ArrayList<TextWatcher>();
}
mListeners.add(watcher);
super.addTextChangedListener(watcher);
}
#Override
public void removeTextChangedListener(TextWatcher watcher) {
if (mListeners != null) {
int i = mListeners.indexOf(watcher);
if (i >= 0) {
mListeners.remove(i);
}
}
super.removeTextChangedListener(watcher);
}
public void clearTextChangedListeners() {
if (mListeners != null) {
for (TextWatcher watcher : mListeners) {
super.removeTextChangedListener(watcher);
}
mListeners.clear();
mListeners = null;
}
}
}
After that final solution will look like this:
final Item designItem = designList.get(position);
holder.et.clearTextChangedListeners();
holder.et.setText(designItem.getEtTxt());
holder.et.addTextChangedListener(new TextWatcher() {
#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) {
designItem.setEtTxt(editable.toString);
}
});
Where et will be of type ExtendedEditText instead of EditText.
I have a ListView with an EditText (quantity box) on each row. When the user sets the desired quantity, the new value updates the corresponding column inside a SQLite database, than I repopulate the ListView with the modified values.
To trigger this process I use the addTextChangedListener on the EditText which works just fine.
My Problem is that the listener is called each time while scrolling, and this triggers the above process, without even touching the quantity box.
How could I avoid the addTextChangedListener to be triggered while scrolling? Same problem happens with my spinner.setOnItemSelectedListener. I have tried to get the listeners outside the getView method but without any luck...:(
the custom ListView:
public class PhotosListViewAdapter extends ArrayAdapter<ImageItemsSetter> {
DeleteImageListener dListener;
private Context context;
private int layoutResourceId;
private ArrayList<ImageItemsSetter> data = new ArrayList<ImageItemsSetter>();
//standard constructor
public PhotosListViewAdapter(Context context, int layoutResourceId, ArrayList<ImageItemsSetter> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
static class ViewHolder {
public ImageView Img;
public EditText quantity;
public Spinner spinner;
public Button delete;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View row = convertView;
ViewHolder holder = null;
ImageItemsSetter image = data.get(position);
if (row == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ViewHolder();
holder.Img = (ImageView) row.findViewById(R.id.Img);
holder.quantity = (EditText) row.findViewById(R.id.quantity);
// holder.quantity.addTextChangedListener(new GenericTextWatcher(holder.quantity));
holder.spinner = (Spinner) row.findViewById(R.id.photo_format);
holder.delete = (Button) row.findViewById(R.id.deleteImage);
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
holder.Img.setImageBitmap(image.getTheImage());
holder.quantity.setText(image.getQuantity());
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context,
R.array.formats_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
holder.spinner.setAdapter(adapter);
//The delete button
holder.delete.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (dListener != null) {
dListener.onDeletePressed(position);
}
}
});
holder.spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
dListener.onFormatChanged(parent.getItemAtPosition(pos).toString(), data.get(position).getName());
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
});
holder.quantity.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) { }
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) { }
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
dListener.onQuantityChanged(s.toString(), data.get(position).getName());
}
});
return row;
}
/*
private class GenericTextWatcher implements TextWatcher {
private View view;
private GenericTextWatcher(View view) {
this.view = view;
}
// 3. saving the quantity box before it gets outside the visible area
#Override
public void afterTextChanged(Editable s) {
final EditText editText = (EditText) view;
dListener.onQuantityChanged(editText.getText().toString(), "tom");
}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
}
*/
//Interface to send selected image's position for deletion
public void setDeleteImageListener(DeleteImageListener listener) {
this.dListener = listener;
}
public static interface DeleteImageListener {
public void onDeletePressed(int position);
public void onQuantityChanged(String quantity, String name);
public void onFormatChanged(String format, String name);
}
Host activity part (here I receive responses using 2 custom interfaces):
#Override
public void onQuantityChanged(String quantity, String name) {
System.out.println("quantity set to: " + quantity + " " + name );
datasource.updateImageQuantiry(name, quantity);
rePopulateList();
}
#Override
public void onFormatChanged(String format, String name) {
System.out.println("format set to: " + format + " name: " + name);
}
Add a scroll listener to your ListView, and set a flag somewhere to know if ListView is scrolling or not.
Then inside onTextChanged, check that flag before calling your listener.
This will work because the method AbsListView.OnScrollListener.onScrollStateChanged gets called before the scroll happens.
public abstract void onScrollStateChanged (AbsListView view, int
scrollState)
Callback method to be invoked while the list view
or grid view is being scrolled. If the view is being scrolled, this
method will be called before the next frame of the scroll is rendered.
In particular, it will be called before any calls to getView(int,
View, ViewGroup).
You can even make your class PhotosListViewAdapter implement the OnScrollListener interface, and then set your adapter as the scroll listener for your ListView. That way you can manage the scrolling flag state inside your adapter.
public class PhotosListViewAdapter extends ArrayAdapter<String> implements AbsListView.OnScrollListener {
public boolean scrolling;
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
scrolling = scrollState != SCROLL_STATE_IDLE ;
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
//...
//TextWatcher.onTextChanged()
//if(!scrolling) dListener.onQuantityChanged(s.toString(), data.get(position));
//...
}
//In your activity or fragment:
//myListView.setOnScrollListener(myPhotoListViewAdapter);
This is because your adapter is setting the text on the views as you scroll, which should kick off your listener.
Also, you should only set your listeners once, not everytime getView() is called.
I am using a custom list view which contains two Buttons Yes or No. When I clicked on No button, a layout containing an edit text will be displayed. There are more than 15 items in the list view. When I tried to type and save the value in the edittext of the 1st item using TextWatcher(), then the value is save for both 5th and 1st position ie, the same value is saving in both 1st and 5th position.
The code I am using is:
holder.subQuestionAnswer.addTextChangedListener( new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
questionsModel.get(position).getQuestion_subquestion().get(0).setAnswer(holder.subQuestionAnswer.getText()
.toString());
Log.e("value", "no_active<>"+position+"<>"+questionsModel.get(position).getQuestion_subquestion().get(0).getAnswer().toString());
}
});
}
How can i avoid this?
It is because of recycling of view. Please check the following adapter. Use the logic according to your needs.
public class MultiSelectionProductAdapter extends ArrayAdapter<ProductListBean> {
private Context context;
private ArrayList<ProductListBean> productList;
private ArrayList<ProductListBean> mOriginalValues;
private LayoutInflater li;
public MultiSelectionProductAdapter(Context ctx, int simpleListItem1,
ArrayList<ProductListBean> data) {
super(ctx, simpleListItem1, data);
this.context = ctx;
this.productList = data;
li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return productList.size();
}
#Override
public ProductListBean getItem(int position) {
return productList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = li.inflate(R.layout.component_inventory_prod_list, null);
holder = new ViewHolder();
holder.tvProductName = (TextView) convertView.findViewById(R.id.tvProductName);
holder.tvProdShortCode = (TextView) convertView.findViewById(R.id.tvShortName);
holder.tvLastOrderedQty = (TextView) convertView.findViewById(R.id.tvLastOrderedQty);
holder.etQty = (EditText) convertView.findViewById(R.id.etQty);
holder.parentRL = (LinearLayout) convertView.findViewById(R.id.parentRL);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final ProductListBean tempBean = productList.get(position);
holder.etQty.setId(position);
final String productName = tempBean.getProductName();
final String productCode = tempBean.getProductCode();
final String productShortCode = tempBean.getProductShortCode();
if (mSelectedProd != null && mSelectedProd.contains(productCode)) {
final int indexOfProd = mSelectedProd.indexOf(productCode);
holder.etQty.setText(mSelectedProducts.get(indexOfProd).getEnteredQty());
}
holder.tvProductName.setText(productName);
holder.tvProdShortCode.setText(productShortCode);
holder.tvLastOrderedQty.setText(tempBean.getLastOrderedQty());
holder.etQty.setText(tempBean.getEnteredQty());
holder.parentRL.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
holder.etQty.requestFocus();
}
});
holder.etQty.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
final int pos = holder.etQty.getId();
final String qty = holder.etQty.getText().toString();
if (qty.length() > 0) {
if (String.valueOf(qty.charAt(0)).equals("0")) {
holder.etQty.setError("Invalid Quantity");
holder.etQty.setText("");
} else {
productList.get(pos).setEnteredQty(holder.etQty.getText().toString());
}
} else {
productList.get(pos).setEnteredQty("");
}
}
});
return convertView;
}
static class ViewHolder {
TextView tvProductName, tvProdShortCode, tvLastOrderedQty;
EditText etQty;
LinearLayout parentRL;
}