Text change event inside listview in android - android

I am new to android and I have a editText inside the listview what I want when the user puts some text or value into the editText this value should get displayed into a textview inside same listitem.I tried to get it done in getView of the custom adapter but its not working for me.My code is like this:
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = lInflater.inflate(R.layout.list_style_task
, parent, false);
}
LItem p = getProduct(position);
tvAQuantity=((TextView) view.findViewById(R.id.tvAQuantity )) ;
((TextView) view.findViewById(R.id.tvMaterial )).setText(p.getMName() );
((TextView) view.findViewById(R.id.tvTask )).setText(p.getTName() );
tvBQuantity=((TextView) view.findViewById(R.id.tvBQuantity )) ;
tvBQuantity.setText(p.getBQ());
etQuantity=(EditText)view.findViewById(R.id.etTaskQuantity);
etQuantity.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) {
if(Integer.parseInt(s.toString())<=Integer.parseInt(tvBQuantity.getText().toString()))
{
tvAQuantity.setText(s.toString());
}
else
{
tvAQuantity.setText(tvBQuantity.getText());
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
// CheckBox cbBuy = (CheckBox) view.findViewById(R.id.checkbox);
//cbBuy.setOnCheckedChangeListener(myCheckChangList);
// cbBuy.setTag(position);
// cbBuy.setChecked(p.selected);
return view;
}
Need your valuable suggestions.

2 Alternatives are:
You have to update respected string into your model class which is to be displayed into textview.
You can call notifyDataSetChanged(); after setText() method in your adapter.This will refresh your List View.

Instead setting text to TextView try updating string value in your list model. You are facing this issue because your model is not getting updated on textchange event.
if(Integer.parseInt(s.toString())<=Integer.parseInt(tvBQuantity.getText().toString()))
{
//update string value in your model.
//tvAQuantity.setText(s.toString());
}
else
{
//update string value in your model.
//tvAQuantity.setText(tvBQuantity.getText());
}

Related

EditText in Listview Strange selection behavior after scroll

I have a problem with EditText-fields in a listview. After i scroll some settings seem to be reset (selectAllOnFocus) and the selection cursor goes bananas.
I have a listview with a custom ArrayAdapter and a custom dataobject. In this case the object only holds one String (to simplify it).
My Activity
// adapter + content
List<ListviewObject> listViewContent = new ArrayList<ListviewObject>();
for(int i = 0; i < 50; i++) {
listViewContent.add(new ListviewObject("num: " + i));
}
adapter = new CustomListAdapter(AddNewPerson.this, R.layout.list_item, listViewContent);
// list
ListView mListView = (ListView)findViewById(R.id.sample_list);
mListView.setItemsCanFocus(true);
mListView.setAdapter(adapter);
My Adapter
#Override
public View getView(int position, View convertView, ViewGroup parent) {
HolderObject holder = null;
if(convertView == null) {
convertView = mLayoutInflater.inflate(layoutResourceId, parent, false);
holder = new HolderObject();
holder.name = (TextView) convertView.findViewById(R.id.txt);
convertView.setTag(holder);
} else {
holder = (HolderObject) convertView.getTag();
}
holder.lvObject = items.get(position);
setNameTextChangeListener(holder);
// Retrieve the correct value
holder.name.setText(holder.lvObject.getName());
return convertView;
}
public static class HolderObject {
ListviewObject lvObject;
TextView name;
}
private void setNameTextChangeListener(final HolderObject holder) {
holder.name.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Update the value
holder.lvObject.setName(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
#Override
public void afterTextChanged(Editable s) { }
});
}
To fix all the focusproblems I found in other threads I've set:
.setItemsCanFocus(true) on the listview
android:descendantFocusability="beforeDescendants" in the activity XML
android:windowSoftInputMode="adjustPan" in the manifest XML
Focussing and editing text works fine. When I scroll the correct values are held and all this seems to work fine.
Before I scroll and I click on some of the EditTexts this happens. (Last focused blurs, clicked one focuses, content is selected)
http://imgur.com/eeIKhCv
After I scroll down and up again, and do the same clicks as before, this happens.
http://imgur.com/75mjPc3
This is due to listView recycling mechanism. To know more about listview recycling mechanism you can refer this link
in your case you avoid the problem by storing a last focused editText and In getView set focus to only last stored integer and skip other position. hope this help you...
It's quite easy:
Declare a String[] to keep track each EditText's input inside the afterTextChanged() of "addTextChangedListener().
Becareful of the order:
viewHolder.editText.removeTextChangedListener(viewHolder.textWatcher);
viewHolder.textWatcher = 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) {
mInputs[position] = editable.toString(); //record input
viewHolder.editText.setSelection(viewHolder.editText.getText().length()); //set cursor to the end
}
};
viewHolder.editText.addTextChangedListener(viewHolder.textWatcher);
viewHolder.editText.setText(mInputs[position]);
Add android:windowSoftInputMode="adjustPan" to your Activity in AndroidManifest file.
Good luck!

how to take the value form edittext in a listview?

I have a custom list with one textView and one
edit text in each row. My question is: whenever user enters
any number inside the edittext,at that time i want to take the
value from the edittext and add it with the previous value and
displayed in the top textview.
For eg. Say inside number of edittext i entered 10 in any
edittext. 10is the first number entered.then it is going to add
with 0.after that if he enter 15 in another edittext,then 10+15 = 25
should be displayed in the top textview.
I got it...
That was as simple as using setOnFocusListener. If the focus gets lost from the edit text.at that the boolean hasFocus parameter gets false. and we can easily collect the value inside the edit text. But thanks for you support guys. Thanks 1ce again.
try this
String content = edtEditText.getText().toString();
tvTextView.setText(content);
You have to Use A TextWatcher on the EditText View like this for That:
EditText editText1 = (EditText) findViewById(R.id.e1);
TextWatcher checker = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (ChecknotNull()) {
TextView1.setText(edittext1.getText().toString().trim());;
Note: You can Also Go on Concating the values with the
previous values Of the TextView(InShort,Perform Logic Here)
}
}
private boolean ChecknotNull() {
return editText1.getText().toString().trim().length() > 0;
}
};
//Set the checker method for the EditText View like this Way
editText1.addTextChangedListener(checker);
I am not sure,this would help...but you can try with this:
Get a setOnFocusListener on your edit text like:
mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View arg0, boolean arg1) {
int s=Integer.parseInt(mEditText.getText().toString());
int ps=Integer.parseInt(mTextView.getText().toString());
mTextView.setText((s+ps)+"");
mEditText.setText("");// clear editText after adding its value to textview
}
});
don't forget to empty the edittext when focus is gone,otherwise when user would click onto edittext even to delete previous one,value would again be added to your textview.
In the Adapter, do this:
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
ViewHolder holder = new ViewHolder();
p = values.get(position);
if (vi == null) {
vi = inflater.inflate(R.layout.feed_items, null);
holder.text = (TextView) vi.findViewById(R.id.tv);
holder.editText = (EditText) vi.findViewById(R.id.et);
holder.editText.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
i++;
int n = Integer.parseInt(holder.text.getText().toString());
int m = Integer.parseInt(s.getText().toString());
holder.text.setText("" + n + m);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){}
public void onTextChanged(CharSequence s, int start, int before, int count){}
});
vi.setTag(holder);
} else {
holder = (ViewHolder) vi.getTag();
}
return vi;
}

how to get all edit text values in array list in customized listview using base adapter in android

I am fetching all menunames from server database through url i append all menunames into editext customized listview using base adapter. now i am getting Edittext changed values into list array .now i want store edittext all values, whether he changes menunames or not.Eg:x,yz... menunames coming from database append to the editext now i am changed menuname y to b and z to c in editext.now i want [x,b.c...] vaules in arraylist but now i am getting b,c
this is my code
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.editmainmenulist, null);
holder.caption = (EditText) convertView
.findViewById(R.id.editmaimenu);
holder.caption1=(ImageView) convertView.findViewById(R.id.menuimage);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//Fill EditText with the value you have in data source
holder.caption.setText(itemnames[position]);//here only i append database menunames
holder.caption.setId(position);
holder.caption1.setImageBitmap(bmps[position]);
//we need to update adapter once we finish with editing
holder.caption.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus){
final int position = v.getId();
final EditText Caption = (EditText) v;
itemnames[position] = Caption.getText().toString();
arr.add(Caption.getText().toString());//here only i think problem..please see any body can tell what i have mistake has been done
}
}
});
return convertView;
}
}
class ViewHolder {
EditText caption;
ImageView caption1;
}
class ListItem {
String caption;
}
i want all edittext values in whether the editext values change or not. for update purpous.
i can get all menunames previous . i want update old menunames into new menunames
Add TextChangedListener to your EditText in getView()
Code:
holder.caption.addTextChangedListener(new TextWatcher()
{
#Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s)
{
// TODO Auto-generated method stub
String data = holder.caption.getText().toString().trim();
}
});
Now get the data from edittext when you want, onTextChanged, beforeTextChanged or afterTextChanged..

How to refer to the original position of a list item when text filter is enabled?

When I use edit text to filter the items, the list positions get all messed up and the items no longer call the proper intent. Any help is appreciated
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String mName = filteredValues.get(position).getName().toString();
String mWeb = filteredValues.get(position).getWebsite().toString();
Intent openDetails = new Intent(Test.this, ResourceDetails.class);
Bundle b = new Bundle();
b.putString("name", mName);
b.putString("web", mWeb);
openDetails.putExtras(b);
startActivity(openDetails);
}
});
private TextWatcher filterTextWatcher = new TextWatcher(){
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s);
adapter.notifyDataSetChanged();
}
public void afterTextChanged(Editable s) {
}
};
flashsearchList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Integer temp=flashSearchNameMap.get(adapter.getItem(position));
navigateSearch(temp);
}
});
(adapter.getItem(position) will return you the exact list name and in flashSearchNameMap i have stored names and position at beginning from oncreate before applying filtering.So you can get exact position by this
if you use ViewHolder in Adapter just define a realPosition variable in holder class and set it in YourAdapter.getView
and in listClick Listener
ContactAdapter.ViewHolder holder = (YourAdapter.ViewHolder) view.getTag();
holder.realPosition
The item position is not reliable when using lists. I recommend you to use view.setTag(Object) to assign an identifier to each item when attaching the content. This could be a number, string or anything. Then you can just access it with view.getTag() inside the click listener.
Assuming you are using a custom bean object to store your name & website values and an ArrayAdapter to show them in your ListView, like so
public class NamedLink {
final String mName;
final String mWebsite;
public NamedLink(String name, String website) {
mName = name;
mWebsite = website;
}
#Override
public String toString() {
return mName;
}
}
With an adapter, defined something like this:
mAdapter = new ArrayAdapter<NamedLink>(this, android.R.layout.simple_list_item_2, mLinks) {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(WhateverYourActivityIsNamed.this).inflate(android.R.layout.simple_list_item_2, null);
}
NamedLink link = getItem(position);
// This probably deserves a ViewHolder
((TextView) convertView.findViewById(android.R.id.text1)).setText(link.getName());
((TextView) convertView.findViewById(android.R.id.text2)).setText(link.getWebsite());
return convertView;
}
};
When you filter the array adapter it will match against the beans #toString(), which in this case returns the name. When filtered, the array adapter maintains a properly indexed copy of your list of beans internally - i.e. you can use the position you get in the click listener like this:
getListView().setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// getItemAtPosition() will return a NamedLink from the filtered
// list maintained inside the ArrayAdapter
NamedLink link = (NamedLink) parent.getItemAtPosition(position);
Intent openDetails = new Intent(Test.this, ResourceDetails.class);
Bundle b = new Bundle();
b.putString("name", link.getName());
b.putString("web", link.getWebsite());
openDetails.putExtras(b);
startActivity(openDetails);
}
});

Android Handling many EditText fields in a ListView

Just a basic question: If I have several dozen EditText fields that are part of a ListAdapter, how can the individual EditText fields know to which row they belong?
Currently I am using TextWatcher to listen for text input. I have tried extending TextWatcher so that I can pass in the position of the EditText to TextWatcher's constructor.
However, when the soft keyboard pops up, the positions that correspond to the various EditText fields shuffle.
How can I track the EditText fields to their proper position?
I am using a GridView to lay things out. The layout of each item is an ImageView with a TextView and EditText field below it.
The text for each EditText is held in a global String array called strings. It is initially empty, and is updated by my TextWatcher class.
public void initList()
{
ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, R.layout.shape, strings)
{
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.shape, null);
}
final String theData = getItem(position);
final EditText editText = (EditText) convertView.findViewById(R.id.shape_edittext);
editText.setText(theData);
editText.addTextChangedListener(
new MyTextWatcher(position, editText)
);
ImageView image = (ImageView) convertView.findViewById(R.id.shape_image);
image.setBackgroundResource(images[position]);
TextView text = (TextView) convertView.findViewById(R.id.shape_text);
if (gameType == SHAPES_ABSTRACT)
text.setText("Seq:");
else
text.setVisibility(View.GONE);
return convertView;
}
#Override
public String getItem(int position) { return strings[position]; }
};
grid.setAdapter(listAdapter);
}
private class MyTextWatcher implements TextWatcher {
private int index;
private EditText edittext;
public MyTextWatcher(int index, EditText edittext) {
this.index = index;
this.edittext = edittext;
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
public void afterTextChanged(Editable s) { strings[index] = s.toString(); }
public void setIndex(int newindex) { index = newindex; }
}
When I click into the first EditText (see picture), the EditText shifts to the one under the smiley face.
Not taking into account if this is a good UI design, here's how you'd do it:
public class TestList
{
public void blah()
{
ArrayAdapter<DataBucket> listAdapter = new ArrayAdapter<DataBucket>()
{
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
}
final DataBucket dataBucket = getItem(position);
final EditText editText = (EditText) convertView.findViewById(R.id.theText);
editText.setText(dataBucket.getSomeData());
editText.addTextChangedListener(new TextWatcher()
{
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
public void afterTextChanged(Editable editable)
{
dataBucket.setSomeData(editable.toString());
}
});
return convertView;
}
};
}
public static class DataBucket
{
private String someData;
public String getSomeData()
{
return someData;
}
public void setSomeData(String someData)
{
this.someData = someData;
}
}
}
'DataBucket' is a placeholder. You need to use whatever class you created to store the data that gets put into and edited in the edit text. The TextWatcher will have a reference to the data object referenced. As you scroll, the edit text boxes should get updated with current data, and text changes should be saved. You may want to track which objects were changed by the user to make data/network updates more efficient.
* Edit *
To use an int position rather than directly referencing the object:
ArrayAdapter<DataBucket> listAdapter = new ArrayAdapter<DataBucket>()
{
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
}
final DataBucket dataBucket = getItem(position);
final EditText editText = (EditText) convertView.findViewById(R.id.theText);
editText.setText(dataBucket.getSomeData());
editText.addTextChangedListener(new TextWatcher()
{
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
{
}
public void afterTextChanged(Editable editable)
{
getItem(position).setSomeData(editable.toString());
}
});
return convertView;
}
};
* Edit Again *
I feel compelled to say for posterity, I wouldn't actually code it this way. I'd guess you want a little more structured data than a String array, and you're maintaining the String array outside, as well as an ArrayAdapter, so its sort of a weird parallel situation. However, this will work fine.
I have my data in a single String array rather than a multi-dimensional array. The reason is because the data model backing the GridView is just a simple list. That may be counterintuitive, but that's the way it is. GridView should do the layout itself, and if left to its own devices, will populate the row with variable numbers of cells, depending on how much data you have and how wide your screen is (AFAIK).
Enough chat. The code:
public class TestList extends Activity
{
private String[] guess;
//Other methods in here, onCreate, etc
//Call me from somewhere else. Probably onCreate.
public void initList()
{
ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, /*some resourse id*/, guess)
{
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
if (convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.testlayout, null);
}
final String theData = getItem(position);
final EditText editText = (EditText) convertView.findViewById(R.id.theText);
editText.setText(theData);
editText.addTextChangedListener(
new MyTextWatcher(position)
);
return convertView;
}
};
gridView.setAdapter(listAdapter);
}
class MyTextWatcher extends TextWatcher {
private int position;
public MyTextWatcher(int position) {
this.position = position;
}
public void afterTextChanged(Editable s) {
guess[position] = s.toString();
}
// other methods are created, but empty
}
}
To track the row number, each listener in EditText has to keep a reference to an item in a list and use getPosition(item) to get the position in a ListView. My example uses Button but I think that it can be applied to EditText.
class DoubleAdapter extends ArrayAdapter<Double> {
public DoubleAdapter(Context context, List<Double> list) {
super(context, android.R.layout.simple_list_item_1, list);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_row, null);
}
// keep a reference to an item in a list
final Double d = getItem(position);
TextView lblId = (TextView) convertView.findViewById(R.id.lblId);
lblId.setText(d.toString());
Button button1 = (Button) convertView.findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// the button listener has a reference to an item in the list
// so it can know its position in the ListView
int i = getPosition(d);
Toast.makeText(getContext(), "" + i, Toast.LENGTH_LONG).show();
remove(d);
}
});
return convertView;
}
}
It might be worth considering whether you need the edit texts to be stored in the list cells? It seems a little bit unnecessary when the user will only be editing one at a time.
Whilst I do not know how your app is designed I would recommend rethinking your user experience slightly so that when an list item is pressed a single text edit appears for them to edit. That way you can just get the list items reference as you normally would with a list adapter, store it whilst the user is editing and update it when they have finished.
i'm not sure if that's a nice design you have, as the EditText content will have a good chance of having problems (shuffling content, missing text) once your listview is scrolled. consider trying out m6tt's idea.
but if you really want to go your way, can you post some code, specifically of your TextWatcher?
I tried to solve this and as you can see there is a simple method - I am posting the answer here as it might be useful for someone.
Not able to get the position when list view -> edit text has a text watcher.
This is the solution that worked for me :
In get view -
when I add the text watcher listener to edit text, I also added the below line
edittext.setTag(R.id.position<any unique string identitiy>, position)
in your afterTextChanged -
int position = edittext.getTag(R.id.position)
Gives the correct position number and you can do modifications based on the position number.

Categories

Resources