Android Bind Spinner to Class - android

I'm having some trouble with the Spinner widget. Given the following code:
ArrayList<Person> people= new ArrayList<Person>();
Person = null;
for(int i = 0; i!= 10; i++) {
p = new Person();
s.setID(i);
s.setName("Name " + i);
people.add(s);
}
I'm using the following code to bind it to a Spinner:
Spinner spinner1 = (Spinner) findViewById (R.id.spinner);
ArrayAdapter<Person> adapter = new ArrayAdapter<Person>(this, android.R.layout.simple_spinner_item, people);
spinner1.setAdapter(adapter);
What I would like is for the value (id) to be hidden but passed when selected, and the name to appear. Any help is appreciated.
Thanks.

If I understand your question correctly you would like the name to appear in the spinner dropdown view. When an item is selected you would like to return the id.
There are 2 ways you can approach this.
The simplest way is to implement a toString() that returns the name in your Person object. The ArrayAdapter will return this value when binding the text values of your object to the dropdown view.
Then in your activity you can set the onItemClickListener for the Spinner and call on the adapter.getItemAtPosition(position) to retrieve the Person object. From that person object you can get your id.
The second approach is to extend the ArrayAdapter and implement the getView and getDropDownView and getItem methods. The getView is responsible for creating the rows you see when you click the spinner. The getDropDownView is responsible for creating the view you see in the spinner. And the getItem method will return the object or in your case the id at that specified position. You should bind the name of the Person element to a textview in your getView and getDropDownView methods. After you've created your custom ArrayAdapter you should set the onItemClicKListener for the Spinner and handle it just as I have mentioned above.
The first approach is simple but the second approach is far superior and will yield much greater control over your adapter, especially when you begin to develop something much more complex.
Hope that helps.

very old post -- just came across looking for something else -- noiced a mistake (probably just oversight)
jagsund is mostly right, accept, he got the definion of getView and GetDropDownView wrong - its actually the opposite of what he said : getView shows the content inside the spinner control, getDropDownView creates the view rows that you see when you click on the spinner.
So, unless you click on the spinner, getDropDownView will not even get called - you'll see this if you override ArrayAdapter

Related

How do I refresh a ListFragment efficiently?

I have a ListFragment with an ArrayAdapter to display a list of objects. I want to refresh the ListFragment's contents. The items themselves change their text a little and also change their order. I have over one hundred items and the only way I've found to do this is clear the list and re-add them, but this feels ineffcient.
For example:
ListFragment display unordered:
Object A
Object D
Object F
Object B
Object E
Object C
ListFragment display ordered:
Object A
Object B
Object C
Object D
Object E
Object F
I set up my ArrayAdapter like this:
mAdapter = new ArrayAdapter<Store>(mContext,
android.R.layout.simple_list_item_1,
OtherClass.list);
mAdapter.setNotifyOnChange(true);
setListAdapter(mAdapter);
"OtherClass" is:
public class OtherClass extends Object {
public ListArray<Object> list;
...
}
The code in question:
mAdapter.clear();
for (Object o : list) {
mAdapter.add(store);
}
I've already read a lot of answers about how it works and how to use mAdapter.notifyDataSetChanged() but none of them solve my problem or answer my question. Is the only way to refresh the list done by adding/removing something from the list?
Whatever you are attaching your adapter to, like say a listView, it can be unattached by setting it to null or to something else.
So instead of the code in question:
1). Sort the list.
2). Then call:
mAdapter = new ArrayAdapter<Store>(mContext,
android.R.layout.simple_list_item_1,
sortedList);
setListAdapter(mAdapter);
I hope this helps, as your question is still a little unclear. Generally if you have a list generated by an adapter, you dont want to be manually digging through the list as it is auto generated for you and doing so takes away from its ease of use.
OP here. My solution is to stick to my original method which is: If you want to modify the list slightly, but have the list refresh so it's updated and also keep the scroll position then the only way to do this is to clear() and refill the list.
Source: http://vikinghammer.com/2011/06/17/android-listview-maintain-your-scroll-position-when-you-refresh/

Setting tags to each item in a ListView in Android?

I have a ListView where I want each item to have an ID number attached to it (not the same as the position number). I was hoping this could be done by setting a tag to each View item in the ListView using setTag() when these Views are being created.
Right now I'm creating the ListView like this:
final ListView listview = (ListView) findViewById(R.id.listView1);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, names);
listview.setAdapter(adapter);
The names variable in the ArrayAdapter parameters above is an ArrayList, and each string value in this list also has a unique ID that I want to link to this string somehow.
Is there any way I can get access to and modify each of the Views with a tag? One idea was to create my own extended class of ArrayAdapter and override the getView() method, but I don't really understand how it works and how I would go about doing this.
Or is there a better way to link IDs with each string like this than adding tags like I'm trying to do?
Create a ViewBinder and set the tags as the ListView is being populated with whatever you need. You can check all properties of the view to determine what tag goes where, so this should be what you're looking for.
myAdapter.setViewBinder(new MyViewBinder());
public class MyViewBinder implements ViewBinder {
#Override
public boolean setViewValue(View view, Object data, String text){
//Since it iterates through all the views of the item, change accordingly
if(view instanceof TextView){
((TextView)view).setTag("whatever you want");
}
}
}
I just used this exact same answer on another question (albeit slightly different) yesterday.
about getView , it works by using a method of recycling views. i will try to explain it in a simple way.
suppose you have tons of items that can be viewed . you don't want to really create tons of views too , since that would take a lot of memory . google thought of it and provide you the means to update only the views that need to be shown at any specific time.
so , if there is an empty space on the listview , it will be filled with a new view . if the user scrolls , the view that becomes hidden is recycled and given back to you on the getView , to be updated with the data of the one that is shown instead .
for example , if you scroll down , the upper view becomes hidden for the end user , but in fact it becomes the exact same view that is on the bottom .
in order to understand how to make the listview have the best performance and see in practice how and why it works as i've talked about , watch this video:
http://www.youtube.com/watch?v=wDBM6wVEO70
as for tags , i think you want to do something else , since the data itself (usually some sort of collection, like an arrayList) already knows where to update , because you get the position via the getView . if you want a specific view to update , you might be able to do so by using a hashmap that keeps upadting , which its key is the position in the collection , and the value is the associated view . on each time you go to getView , you need to remove the entry that belong to the view (if exists) and assign the new position with the view that you got/created .
Thanks for the answers. thisMayhem's answer would probably have been easier in the end, but on my quest to learn more I ended up making my own adapter according to this tutorial. I pass down the names and the IDs into the adapter and set the names as the text of the TextViews and the IDs as the tags.
I would rather go with the solution discussed in this thread. It is always the easiest to have all related data in same place and in this case you just create a class to hold all the information you will need for every item.

set different color on each listview row

I have seen related answers and I do not know ehich one is the appropriate for me.
I have a listView and each row has a textview. I want given some conditions, each row to get different color.(Imagine that I am getting data from a DB, and given the value I get, i want text set to different color) My code is shown below:
public class TrailsConditionScreen extends ListActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
seeTrails();
}
private void seeTrails() {
String[] help=new String[] {"foo","bar"};
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,R.layout.row,R.id.text1,help);
setListAdapter(adapter);
}
}
This code so far just prints them on the list.
Now I want when retrieving values from the db, given the value i get set a different color on each row. imagine that my codes retrieves data from a table an I want when reading the first line , given the number set the appropriate color on the first line of the listview. Then go to second lone of the db,set color for the second line of the list and so on.. i have successfully implemented the reading from the db but i do not know how to set color on specific row. In pseudo-code it looks like this.
for i=0 to number of lines in db{
read_data();
if key_value=0 then color_of_line(i)=red;
else color_of_line_i)=green;
}
Any help for this?
You must create a custom adapter to handle this instead of using the ArrayAdapter. Extend the ArrayAdapter and override the getView method. And inside the getView method based on the condition you can change the color of the text on your textView.setTextColor.
To write a custom adapter check the tutorial here (6. Tutorial: Implementing your own adapter). This example doesn't use the holder pattern but you should.
Your best bet is to extend ArrayAdapter and create your own class.
In the getView() method, execute your condition and set the color to be drawn. There are a lot of good tutorials on creating your own adapters. Check, for instance, http://www.ezzylearning.com/tutorial.aspx?tid=1763429&q=customizing-android-listview-items-with-custom-arrayadapter.
Hope it helps!
Inorder to achieve this, you will need to use a custom adapter. Since you mentioned, you are getting the data from a database, I am assuming here that you will have information in a cursor adapter. Hence, a good place to start would be to extend cursor adapter.
Within your new custom adapter, you should override getView() method. The view to be used for each item in list view is specified there. Additionally, you can also set the properties of the view there.
Depending on your business logic, you should set the text color in getView.
A tutorial here:
http://www.ezzylearning.com/tutorial.aspx?tid=1763429&q=customizing-android-listview-items-with-custom-arrayadapter
What I would do is create a CustomAdapter for the list view
public class MyCustomAdapter extends BaseAdapter
and in the funcion
public View getView(int position, View convertView, ViewGroup parent)
you have the position and you can change whatever you want.
If you search google by custom adapter listview you will get some examples
Different Color For different list item ,yes this can be achieved only if items are static only , but for dynamic content it's hard to do ...

How to get each menu item from a list view by position?

Let's say a list has 4 items, how can I get a view from each menu item of a list by position?
Unfortunately the items that are in the ListView are generally only those that are visible. You should iterate on the ListAdapter instead.
For example, in some of my code, I have this:
SimpleCursorAdapter adapter = (SimpleCursorAdapter) this.getListAdapter();
int iNum = adapter.getCount();
for(int i=0; i<iNum; i++)
{
Cursor c = (Cursor) adapter.getItem(i);
// Now you can pull data from the cursor object,
// if that's what you used to create the adapter to start with
}
EDIT:
In response to jeffamaphone's comments, here's something else... if you are trying to work with each UI element then getChildAt is certainly more appropriate as it returns the View for the sub-item, but in general you can still only work with those that are visible at the time. If that's all you care about, then fine - just make sure you check for null when the call returns.
If you are trying to implement something like I was - a "Select All / Select None / Invert Selection" type of feature for a list that might exceed the screen, then you are much better off to make the changes in the Adapter, or have an external array (if as in my case, there was nowhere in the adapter to make the chagne), and then call notifyDataSetChanged() on the List Adapter. For example, my "Invert" feature has code like this:
case R.id.selectInvertLedgerItems:
for(int i=0; i<ItemChecked.length; i++)
{
ItemChecked[i] = !ItemChecked[i];
}
la.notifyDataSetChanged();
RecalculateTotalSelected();
break;
Note that in my case, I am also using a custom ListView sub-item, using adapter.setViewBinder(this); and a custom setViewValue(...) function.
Furthermore if I recall correctly, I don't think that the "position" in the list is necessarily the same as the "position" in the adapter... it is again based more on the position in the list. Thus, even though you are wanting the "50th" item on the list, if it is the first visible, getChildAt(50) won't return what you are expecting. I think you can use ListView.getFirstVisiblePosition() to account and adjust.
See here, this question answers the similar problem you mentioned here
In an android ListView, how can I iterate/manipulte all the child views, not just the visible ones?

How to remove the filter on an ArrayAdapter used in an AutoCompleteTextView?

As the title, how can I remove the filtering on an ArrayAdapter used by an AutoCompleteTextView to get the original list back?
A little more background:
It all started from the sad fact that the "position" value passed in to onItemClick() is useless. The "position" refers to the position AFTER the array has been filtered, but I need to know its REAL position. So, what I'm trying to do is when I've got the text of the selected item (by using getItemAtPosition(position)), I compare it one-by-one with the original string array that backs the ArrayAdapter. However, I found that when onItemClick() is called, the adapter is already filtered, I no longer have access to the original array. So I thought if I can remove the filter, maybe I can get back the original array and look for the selected item in it.
ArrayAdapter<String> mAdapter;
public void onCreate() {
// Create an adapter and remembere it as a class member.
mAdapter = new ArrayAdapter<String>(this, layoutId);
// Add 100 strings to it and attach it to an AutoCompleteTextView
for (int i = 0; i < 100; i++)
mAdapter.add("random text");
((AutoCompleteTextView)findViewById(id)).setAdapter(mAdapter);
}
#Override
public void onItemClick(AdapterView<?> actv, View view, int position, long id) {
if (actv.getAdapter().equals(mAdapter))
Log.d("The adapter contained in actv is the same one I created earlier.");
// And, I can get the text of the item the user selected
String selected = (String)actv.getItemAtPosition(position);
// However, although the adapter passed in is still the same one, but the
// number of items in it is only 1! Because the array has been filtered.
int numItems = actv.getAdapter.getCount();
// So, I'm thinking if I can somehow remove the filtering here, then I can
// get back those 100 items, and do a search like following:
for (int i = 0; i < actv.getAdapter.getCount(); i++)
if (selected == actv.getAdapter.getItem(i))
break; // Eureka!!!
}
To tackle the problem of obtaining the REAL position of the selected item:
Is there a way to utilize the "id" value? Like, assign each item an id, then hopefully onItemClick() would pass back the correct id.
Like I said above, remove the filter (is it possible), get back the original 100 items, and perform a one-by-one search.
This is the last resort, I know it'll work, but I don't want to do it: Once I get the text of the selected text, I go back to the source of the data (from a database), query those 100 items out, and perform the search.
Another lame last resort: To avoid the overhead on accessing the database again as in #3, when in onCreate(), while creating the ArrayAdapter, I use an ArrayList of my own to remember all those 100 strings.
Am I doing it all wrong? What's the "right" way of obtaining the real position of the selected item from an AutoCompleteTextView?
Thank you very much!
(I read somewhere, some buy that seemed to be from Google Android team, said that one should use getFirstVisiblePosition() to resolve the position. But I can't figure out how.)
I don't know if you're still interested, but I found this answering a similar question: Problem with AutoCompleteTextView and Spinner using the same Adapter
Copying the method in the AutoCompleteTextView source code:
Filter filter = mAdapter.getFilter();
filter = null;
See my response in the above question for the grepcode link.
This is actually pretty simple to solve.. Instead of adding each element to the adapter as you get it (I'm assuming your random text part is just for example purposes), instead use the following:
First build your array into a variable, call it myArray..
then initialize your adapter like this:
mAdapter = new ArrayAdapter<String>(this, layoutId, myArray);
Now make sure that myArray is a class variable so you can reference it from anywhere else in the class.. Of course if you need access to this from another class you'd want to make a getter for it... Then you can easily iterate over the array to see if the value selected is in the array.. You'll have the whole set of data there instead of trying to get it from the adapter.
Here is a good example on using a validator for a similar looking use case:
Android, Autocomplettextview, force text to be from the entry list
In my case, I have address that can be set either by autocomplete or clicking on the map. If user click on the map, editText text should be set to address selected from the map, and in that case filtering should be disable temporarily.
I code like this:
public void OnAddressFound(String address) {
// Temporary disable autocomplete
editTextSearch.setAdapter(null);
editTextSearch.setText(address);
// Enable autocomplete again
setAutoCompleteAdapter();
}
where setAutoCompleteAdapter() is called during onCreate, and again in temporary disable/enable filter:
void setAutoCompleteAdapter() {
PlacesAutoCompleteAdapter adapter = new PlacesAutoCompleteAdapter(this, R.layout.item_autocomplete_map_search, autoCompleteList);
editTextSearch.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
Hope its help you also.
I found the solution, kinnda tricky but its works
after i looking inside of the source, i found that th treshold variable used as filtering validation, here we just need to set the treshold to maximum int so filtering never perform.
threshold = Integer.MAX_VALUE
or
setThreshold(Integer.MAX_VALUE)

Categories

Resources