I have EditText inside ListView for inline editing. The user can modify its value & the values are then stored in the SQLite database.
I am using Custom DataAdapter for populating ListView.
There are 15 rows in the listview. at a time 4 rows are visible, to see other rows scrollbar is used (Up / Down)
Issue:
ListView is loaded for the first time. User writes into the EditText 1,2,3,4 in each EditText.
The Scrollbar is moved down & one by one the user enters data into all the rows.
When the user moves the Scroll bar UP to see the first 4 rows... the 4th row shows wrong data instead of 4 it shows 14, which is the last value entered by the user (OR my have some other random value forexample 10/13/11 etc)
In my Custom DataAdapter class i am storing the user input into the datasource when the EditText loses Focus as shown below:
public View getView(int position, View convertView, ViewGroup parent) {
//txtComments is an EditText
holder.txtComments.setId(position);
holder.txtComments.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus){
final int position = v.getId();
final EditText tempComments = (EditText) v;
// items: the DataSource for the listView
items.get(position).Comments = tempComments.getText().toString();
}
}
});
}
EDIT:
I have also tried the TEXTWATCHER but it doest not work for me.
After extensive testing; we found that this issue occures randomly for example sometimes ExitText11 will show wrong value another time ExitText4 will show wrong value OR both of them will show wrong values & this behaviour changes while moving scrollbar up down.
Related
Maybe there is a simple solution to my problem, but i´m not able to find it.
I have a ListView with a list of users. Each row has an EditText to enter the username. I want to set hint text for each user like: "user1, user2, user3, etc", used as default name. The user can click on the EditText and change this name, so the hint text dissapears and the user can enter his name, or leave this default name if he wants.
When the ListView is too long, I have the problem of the view recycling, that duplicates the names. I solved it by using a setOnFocusChangeListener for the EditText, and storing the name for each row, and it´s working fine, but I´d like that when I have a long list, keep the hint text or text introduced by the user for each EditText when scrolling the list.
I don´t know how to modify my adapter to set the name/hint for each EditText.
Any idea?
Thanks a lot.
Create one list in your activity
List<String> yourlist = new ArrayList();
yourlist.add("user1");
yourlist.add("user2");
yourlist.add("user3");....
pass this list to adapter then in adapter,
holder.youredittext.setHint(yourlist.get(position));
if your passing number of items to adapter then create one model class then pass to adapter.
I have an adapter like this:
public View getView(final int position, View convertView, ViewGroup parent)
{
View item = convertView;
if(item == null)
{
LayoutInflater inflater = context.getLayoutInflater();
item = inflater.inflate(R.layout.setup_jugador, null);
holder = new ViewHolder();
holder.nombre = (EditText) item.findViewById(R.id.nombre);
// Establecemos el tag
item.setTag(holder);
}
else
{
holder = (ViewHolder)item.getTag();
}
holder.nombre.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if(!hasFocus){
EditText et = (EditText) v.findViewById(R.id.nombre);
// Here I store the name
jugadores.get(position).setNombre(et.getText().toString());
}
}
});
// Update EditText
holder.nombre.setText(jugadores.get(position).getNombre());
// Another option is
holder.nombre.setHint(jugadores.get(position).getNombre());
return(item);
}
jugadores is a list that stores the names. Initially it has user1, user2, etc.
I could setHint when Item==null, but I have to update the text at the end of the adapter, and when scrolling, the view recycling changes the items that are invisible.
I only see 8 items, and when scrolling, if I change first item, item number 9 also change. If I use setText, it becomes black, and if I use setHint, first item becomes grey.
I can´t put hint value in layout because I´d like to add the row number to the name. I tried using a boolean value in the class used as model in the adapter to show that the name has been modified, check this value using position index in the list, and use setText or setHint according to that, but doesn´t work.
I am creating one view from XML, I have defined one row in xml and in my main layout I am adding it through layout inflator and setting the id's of component( TextView, EditText, Button) run time. I have three requirements
User can add new row( It is done)
User can delete row ( It is done
I need to fetch the data from the created row. ( It is done too)
I am following this tutorial
https://github.com/laoyang/android-dynamic-views#readme and it is great tutorial as well.
I am creating the ID of each component at run time and adding it to arraylist so that I can fetch the data from it through loop. i.e
for (EditText editText : Quanitity) { }
Problem is that when user presses the delete button on each row, It deletes the row from the layout and its components as well through this code:
Main.removeView((View) v.getParent());
but its corresponding components ID's are already added to the arraylist. I want when user presses the delete button of the row I should get the position of it so that I can remove it through the arraylist as well.
Each row has a textview which is spinner style. I want to open the spinner on click of textview and value should be set for that Textview not all rows.
Please help me in this case. I am really stucked and deadline is today.
Thanks
aray
First thing to achieve this is to get your selected view's ID and after that search the arraylist for that id and if found delete it.That should look something similar to this :
int myEditTextID = myEditText.getId(); // ids of your selected editext
ids.remove(ids.indexOf(myEditTextID)); // ArrayList<Integer> where you are storing your ids.
The code above first get the id of your selected edittext and than search for the it's index in your arraylist and remove it.
That's all! : )
You can get the index of the child in the ViewGroup with indexOfChild(View). You may need to subtract an offset from that index depending on how many child views come before the rows you are adding (if any).
http://developer.android.com/reference/android/view/ViewGroup.html#indexOfChild(android.view.View)
public void onDeleteClicked(View v) {
// get index
int index = mContainerView.indexOfChild((View) v.getParent()) - offset;
// remove from ArrayList
myArrayList.remove(index);
// remove the row by calling the getParent on button
mContainerView.removeView((View) v.getParent());
}
You can get the offset by storing the initial index of the ViewGroup that you will be adding the views (rows) at before you add any. Which, in the case of the link provided (although unnecessary since it equals 0), would be something like this:
private int offset = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
...
// this should be equal to the index where the first row will be inserted
// offset = 0 with the code in your link
offset = mContainerView.getChildCount() - 1;
// Add some examples
inflateEditRow("Xiaochao");
inflateEditRow("Yang");
}
I'm displaying entries from SQLite database in Expandable ListView and everything is working correctly but, I wanted to add in a checkbox right next to all children. Every time I check a checkbox and then scroll down or contract the checkbox which I had checked it doesn't save the state of the checkbox. I know that the list is recycled whenever I scroll down and expand the groups and so forth. How can I save the state of every checkbox (by every child)? I have a class which extends CursorTreeAdapter and there is no "childPosition" in the methods. What do I need to do in order to save the state?
you can have an array of boolean flags with same size as sum of list elements and set and get the checked value from this array for any component.
One more solution is you can hold a counter for each element in list view. For example if you have Person list, you can add one counter variable in your Person class.
And in getChildView method, put all codes in an if block like below;
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, final ViewGroup parent) {
//FOR SAVE THE STATES!!
if(parents.get(groupPosition).getCounter()==0) {
DatePicker datePicker = null;
Button ok = null;
Spinner installment = null;
CheckBox creditCard;
......//BLA BLA BLA
//After finish your codes, increment the counter
parents.get(groupPosition).setCounter((parents.get(groupPosition).getCounter()+1));
}
return convertView;
}
Because for each expandGroup method called, all the initializations (for now those are in if block) repeats. Because of that you loose your state of objects.
Hope this help.
So I have a spinner (spinner2 here) which is populated via an ArrayAdapter from an SQLite table. On selecting an item I want it
deleted from the DB
deleted from the spinner
The code below actually works. Except when the spinner has only one item. When that happens
it seems onItemSelected is not called at all.
I get the following LogCat
10-01 22:30:55.895: WARN/InputManagerService(1143): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy#45a06028
Oh and when two items are populating the spinner, spinner.getcount() shows two items, so it's not some strange case of the system thinking the spinner is empty or something like that.
This is the code:
public class SpinnerItemSelectListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if(parent == spinner2){
if(autoselected){
autoselected=false;
}
else{
//uniqvalarray is the arraymade from pulling data from SQLite and populaitng array adapter
Integer i = uniquevalarray.get(pos);
deleteRow(i);//deletes the row from the database and repopulates the above array.
autoselected=true;//just a boolean to stop autoslecting in onCreate()
//makeAlert(i);initially wanted to make alert box.
loadSpinner2();//reloads the spinner with new data
}
}
}
public void onNothingSelected(AdapterView parent) {
//TODO
}
}
The spinner runs this way : Only fire when you change the selected item . If you dont change that element , cause its the only one that exist , it can't change .
The solution i think you must use is using a button next to the spinner to throw the delete funcions.
You must think that Spinner is not made to be with an unique element , cause only changes usually when you change the selected one . then the natural solution can be that .
I have created a custom Array Adapter to bind a custom row that contains some static text and an editable EditText. I am trying to register to be notified when the user changes the text within the edit text and when notified to determine which ArrayList row the modified EditText corresponds to.
In the past with other types of views such as a Spinner I could simply put a reference to the parent view and the row number into the tag for the Spinner view. And then when I was notified that the value changed I read the tag to determine how to correlate it back to the master ArrayList.
The problem with registering to be notifed with an EditText change is that you do not get back a view but instead get a TextWatcher and I have no way to correlate back to the parent view or ArrayList row.
What is the technique that you need to use in this circumstance?
You can use onEditorAction on your EditText in your ArrayAdapter:
mEditText.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
// Parse parent tree to find position of view
int position = 0;
View v = null;
while (view != v && position < mListView.getChildCount())
v = mListView.getChildAt(position++);
// do something
something(position);
// do not consume the action
return false;
}
});
Note that using this method, you are going to trigger an event only when user press "ok", "enter", "done", etc. on the keyboard.