I am working on an android project and I am using a spinner which uses an array adapter which is populated from the database.
I can't find out how I can set the selected item programmatically from the list. For example if, in the spinner I have the following items:
Category 1
Category 2
Category 3
How would I programmatically make Category 2 the selected item when the screen is created. I was thinking it might be similar to c# I.E Spinner.SelectedText = "Category 2" but there doesn't seem to be any method similar to this for Android.
Use the following:
spinnerObject.setSelection(INDEX_OF_CATEGORY2).
No one of these answers gave me the solution, only worked with this:
mySpinner.post(new Runnable() {
#Override
public void run() {
mySpinner.setSelection(position);
}
});
public static void selectSpinnerItemByValue(Spinner spnr, long value) {
SimpleCursorAdapter adapter = (SimpleCursorAdapter) spnr.getAdapter();
for (int position = 0; position < adapter.getCount(); position++) {
if(adapter.getItemId(position) == value) {
spnr.setSelection(position);
return;
}
}
}
You can use the above like:
selectSpinnerItemByValue(spinnerObject, desiredValue);
& of course you can also select by index directly like
spinnerObject.setSelection(index);
Some explanation (at least for Fragments - never tried with pure Activity). Hope it helps someone to understand Android better.
Most popular answer by Arun George is correct but don't work in some cases. The answer by Marco HC uses Runnable wich is a last resort due to additional CPU load. The answer is - you should simply choose correct place to call to setSelection(), for example it works for me:
#Override
public void onResume() {
super.onResume();
yourSpinner.setSelection(pos);
}
But it won't work in onCreateView(). I suspect that is the reason for the interest to this topic.
The secret is that with Android you can't do anything you want in any method - oops:( - components may just not be ready. As another example - you can't scroll ScrollView neither in onCreateView() nor in onResume() (see the answer here)
To find a value and select it:
private void selectValue(Spinner spinner, Object value) {
for (int i = 0; i < spinner.getCount(); i++) {
if (spinner.getItemAtPosition(i).equals(value)) {
spinner.setSelection(i);
break;
}
}
}
Why don't you use your values from the DB and store them on an ArrayList and then just use:
yourSpinner.setSelection(yourArrayList.indexOf("Category 1"));
The optimal solution is:
public String[] items= new String[]{"item1","item2","item3"};
// here you can use array or list
ArrayAdapter adapter= new ArrayAdapter(Your_Context, R.layout.support_simple_spinner_dropdown_item, items);
final Spinner itemsSpinner= (Spinner) findViewById(R.id.itemSpinner);
itemsSpinner.setAdapter(adapter);
To get the position of the item automatically add the following statement
itemsSpinner.setSelection(itemsSpinner.getPosition("item2"));
You can make a generic method for this kind of work as I do in my UtilityClass which is
public void SetSpinnerSelection(Spinner spinner,String[] array,String text) {
for(int i=0;i<array.length;i++) {
if(array[i].equals(text)) {
spinner.setSelection(i);
}
}
}
You can easily set like this: spinner.setSelection(1), instead of 1, you can set any position of list you would like to show.
I have a SimpleCursorAdapter so I have to duplicate the data for use the respose in this post. So, I recommend you try this way:
for (int i = 0; i < spinnerRegion.getAdapter().getCount(); i++) {
if (spinnerRegion.getItemIdAtPosition(i) == Integer
.valueOf(signal.getInt(signal
.getColumnIndexOrThrow("id_region")))) {
spinnerRegion.setSelection(i);
break;
}
}
I think that is a real way
In Kotlin I found a simple solution using a lambda:
spinnerObjec.post {spinnerObjec.setSelection(yourIndex)}
This is what I use in Kotlin:
spinner.setSelection(resources.getStringArray(R.array.choices).indexOf("Choice 1"))
I know that is already answered, but simple code to select one item, very simple:
spGenre.setSelection( ( (ArrayAdapter) spGenre.getAdapter()).getPosition(client.getGenre()) );
This is work for me.
spinner.setSelection(spinner_adapter.getPosition(selected_value)+1);
This is stated in comments elsewhere on this page but thought it useful to pull it out into an answer:
When using an adapter, I've found that the spinnerObject.setSelection(INDEX_OF_CATEGORY2) needs to occur after the setAdapter call; otherwise, the first item is always the initial selection.
// spinner setup...
spinnerObject.setAdapter(myAdapter);
spinnerObject.setSelection(INDEX_OF_CATEGORY2);
This is confirmed by reviewing the AbsSpinner code for setAdapter.
If you have a list of contacts the you can go for this:
((Spinner) view.findViewById(R.id.mobile)).setSelection(spinnerContactPersonDesignationAdapter.getPosition(schoolContact.get(i).getCONT_DESIGNATION()));
for (int x = 0; x < spRaca.getAdapter().getCount(); x++) {
if (spRaca.getItemIdAtPosition(x) == reprodutor.getId()) {
spRaca.setSelection(x);
break;
}
}
Most of the time spinner.setSelection(i); //i is 0 to (size-1) of adapter's size
doesn't work. If you just call spinner.setSelection(i);
It depends on your logic.
If view is fully loaded and you want to call it from interface I suggest you to call
spinner.setAdapter(spinner_no_of_hospitals.getAdapter());
spinner.setSelection(i); // i is 0 or within adapter size
Or if you want to change between activity/fragment lifecycle, call like this
spinner.post(new Runnable() {
#Override public void run() {
spinner.setSelection(i);
}
});
Here is the Kotlin extension I am using:
fun Spinner.setItem(list: Array<CharSequence>, value: String) {
val index = list.indexOf(value)
this.post { this.setSelection(index) }
}
Usage:
spinnerPressure.setItem(resources.getTextArray(R.array.array_pressure), pressureUnit)
This Worked For me:
mySpinner.post(new Runnable() {
#Override
public void run() {
mySpinner.setSelection(position);
spinnerAdapter.notifyDataSetChanged();
}
});
Yes, you can achieve this by passing the index of the desired spinner item in the setSelection function of spinner. For example:
spinnerObject.setSelection(INDEX_OF_CATEGORY).
In my case, this code saved my day:
public static void selectSpinnerItemByValue(Spinner spnr, long value) {
SpinnerAdapter adapter = spnr.getAdapter();
for (int position = 0; position < adapter.getCount(); position++) {
if(adapter.getItemId(position) == value) {
spnr.setSelection(position);
return;
}
}
}
I had made some extension function of Spinner for loading data and tracking item selection.
Spinner.kt
fun <T> Spinner.load(context: Context, items: List<T>, item: T? = null) {
adapter = ArrayAdapter(context, android.R.layout.simple_spinner_item, items).apply {
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
}
if (item != null && items.isNotEmpty()) setSelection(items.indexOf(item))
}
inline fun Spinner.onItemSelected(
crossinline itemSelected: (
parent: AdapterView<*>,
view: View,
position: Int,
id: Long
) -> Unit
) {
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
itemSelected.invoke(parent, view, position, id)
}
}
}
Usaage Example
val list = listOf("String 1", "String 2", "String 3")
val defaultData = "String 2"
// load data to spinner
your_spinner.load(context, list, defaultData)
// load data without default selection, it points to first item
your_spinner.load(context, list)
// for watching item selection
your_spinner.onItemSelected { parent, view, position, id ->
// do on item selection
}
This worked for me:
#Override
protected void onStart() {
super.onStart();
mySpinner.setSelection(position);
}
It's similar to #sberezin's solution but calling setSelection() in onStart().
I had the same issue since yesterday.Unfortunately the first item in the array list is shown by default in spinner widget.A turnaround would be to find the previous selected item with each element in the array list and swap its position with the first element.Here is the code.
OnResume()
{
int before_index = ShowLastSelectedElement();
if (isFound){
Collections.swap(yourArrayList,before_index,0);
}
adapter = new ArrayAdapter<String>(CurrentActivity.this,
android.R.layout.simple_spinner_item, yourArrayList);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item; yourListView.setAdapter(adapter);
}
...
private int ShowLastSelectedElement() {
String strName = "";
int swap_index = 0;
for (int i=0;i<societies.size();i++){
strName = yourArrayList.get(i);
if (strName.trim().toLowerCase().equals(lastselectedelement.trim().toLowerCase())){
swap_index = i;
isFound = true;
}
}
return swap_index;
}
Related
I have been using Thomashaertel's library as a multi-select spinner.
Unless I select all the items, there is no issue but when I select all
the items, It doesn't display the selected item in the textview.
I tried looking for the solution but failed.
Lemme know if anyone has resolved that issue.
This is how I am creating the list. Is there some issue with the way I am creating it or there is some issue with the Library itself??
spinner = new MultiSpinner(context);
adapter = ArrayAdapter.createFromResource(context,
R.array.data_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
I am getting the array from the String resource file.
Yeah, even I had the same problem a few weeks back. It seems to be an issue of the library. I had raised the issue on Github too but no response.
I don't have the solution for this one but have a hack.
Instead of using the multispinner's textview,
you can make use of regular textview and add onClickListener to it.
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spinner.callOnClick(); // call spinner's onClick when textview is clicked
}
This lets you render the dialog with multiselect options.
Now maintain a stringbuilder.
Set the adapter on the spinner and override onItemsSelected(boolean)
and follow the below code
public void onItemsSelected(boolean[] selected) {
stringbuilder = new StringBuilder();
for (int i = 0; i < adapter.getCount(); i++) {
if (selected[i]) {
list.add(String.valueOf(adapter.getItem(i).toString())); //get the list of selected items
if (stringbuilder.length() == 0) {
stringbuilder.append(adapter.getItem(i));
} else {
stringbuilder.append(",").append(adapter.getItem(i));
}
textView.setText(String.valueOf(stringbuilder));
} else {
list.remove(adapter.getItem(i).toString()));
}
}
if (stringbuilder.length() == 0) {
textView.setText(" Make your selection");
}
}
It looks clean compared to the view that multispinner gives and also you have to customize
advantage.
Hope it is useful
hi i am developing one app where i have implemented recycler view and searchview in fregement.i get the filter product first time according to text change.
But when i delete text one by one all list will be empty.Notheing can display at the end .
Here is my code from my fragement
You are continuously operating on single array named plistarray
here in filter() method you have cleared plistarray and again used the same to find the records. so you should use some other array for you adapter rather than plistarray
public void filter(String text) {
if (text.isEmpty()) {
plistarray.clear();
plistarray.addAll(plistarray);
} else {
ArrayList<ProductList> result = new ArrayList<>();
text = text.toLowerCase();
//after clearing the array again you are using same array to find the items from
for (ProductList item : plistarray) {
if (item.getPtitle().toLowerCase().contains(text)) {
result.add(item);
}
}
//you have cleared all the contains here
plistarray.clear();
// and added only result related items here
plistarray.addAll(result);
}
notifyDataSetChanged();
}
I think the problem is in the if (text.isEmpty()) { block of filter method.
Here you clear the plistarray list and add that empty list in plistarray.addAll(plistarray);
Instead of this add your original datalist for the plistarray.addAll(); This will resolve your empty list problem.
Remember this, when you perform the search always first make a dummy/copy of original list in constructor of adapter, and use this dummy to restore the data.
Hope, this will solve your problem.
As i see the main problem is you're manipulating the List your adapter is populated from, but you do not have a "copy" of the original dataset.
Something like this should work:
ArrayList<ProductList> plistarray; // these are instance variables
ArrayList<ProductList> plistarrayCopy; // in your adapter
// ...
public void filter(String text) {
if (plistarrayCopy == null) {
plistarrayCopy = new ArrayList<>(plistarray);
}
if (text.isEmpty()) {
plistarray.clear();
plistarray.addAll(plistarrayCopy);
plistarrayCopy = null;
} else {
text = text.toLowerCase();
ArrayList<Device> filteredList = new ArrayList<>();
for (ProductList pList : plistarrayCopy) {
if (pList.getPtitle().toLowerCase().contains(text)) {
filteredList.add(pList);
}
}
plistarray.clear();
plistarray.addAll(filteredList);
}
notifyDataSetChanged();
}
My application is returning the latest data from firebase to the buttom of the ListView. But I want it to be on the top! I have thought about it and I think there is only two possible ways to do it.
1. Invert the Listview.
I think that this way is how it should be done but I couldn't figure it out. I have searched a lot on the web but no suitable solution for my case
This is my adapter code
public void onStart() {
super.onStart();
// Setup our view and list adapter. Ensure it scrolls to the bottom as data changes
final ListView listView = getListView();
// Tell our list adapter that we only want 50 messages at a time
mChatListAdapter = new ChatListAdapter(mFirebaseRef.limit(50), this, R.layout.chat_message, mUsername);
listView.setAdapter(mChatListAdapter);
}
And this is the code for the ChatListAdapter constructor for a custom list class ChatListAdapter which extends special list adapter class FirebaseListAdapter:
public ChatListAdapter(Query ref, Activity activity, int layout, String mUsername) {
super(ref, Chat.class, layout, activity);
this.mUsername = mUsername;
}
[Edit] This is some of the code for FirebaseListAdapter which extends BaseAdapter class
public FirebaseListAdapter(Query mRef, Class<T> mModelClass, int mLayout, Activity activity) {
this.mRef = mRef;
this.mModelClass = mModelClass;
this.mLayout = mLayout;
mInflater = activity.getLayoutInflater();
mModels = new ArrayList<T>();
mModelKeys = new HashMap<String, T>();
// Look for all child events. We will then map them to our own internal ArrayList, which backs ListView
mListener = this.mRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
T model = dataSnapshot.getValue(FirebaseListAdapter.this.mModelClass);
mModelKeys.put(dataSnapshot.getKey(), model);
// Insert into the correct location, based on previousChildName
if (previousChildName == null) {
mModels.add(0, model);
} else {
T previousModel = mModelKeys.get(previousChildName);
int previousIndex = mModels.indexOf(previousModel);
int nextIndex = previousIndex + 1;
if (nextIndex == mModels.size()) {
mModels.add(model);
} else {
mModels.add(nextIndex, model);
}
}
}
2. Descending query the data.
The second way seams impossible to me, because when I searched on Firebase API documentation and on the web, I couldn't find anyway to order retraived data on descending way.
My data on firebase look like the following:
glaring-fire-9714
chat
-Jdo7-l9_KBUjXF-U4_c
author: Ahmed
message: Hello World
-Jdo71zU5qsL5rcvBzRl
author: Osama
message: Hi!
Thank you.
A simple solution would be to manually move the newly added data to the top of the listview. As you rightly noticed, new data added to a listview will automatically be appended to the bottom of the list, but you may freely move entries once they are added. Something like the following would help you manually move the newest entry to the top of the list:
int iSwapCount = listView.getCount() - 1;
int iPosition = listView.getCount() - 1;
for (int j = 0; j < iSwapCount; j++)
{
Collections.swap(yourlistobject, iPosition, iPosition - 1);
iPosition = iPosition - 1;
}
The above code will begin by calculating the number of swaps that will be required to move last list entry to the top of the list, which is determined by the number of elements in the list - 1. The same is true for calculating the last position in the list. From there Collections.swap will be used to swap the last element in the list with the element before it; this will be repeated until the last element is now the first element, with the rest of the entries in the list remaining in the same order. This code would have to be called each time a new entry is added so that the overall order of the list is maintained.
I realize it has been a while since you asked but I had the same issue. It does not appear that there is a direct answer here.
Here's the change to the firebase adapter to get new items on the top of the list.
Notice the change from add(...) to add(0,...) and add(next...) to add(prev...)
Look for comments:
// prepend instead append
Example:
...
// Insert into the correct location, based on previousChildName
if (previousChildName == null) {
mModels.add(0, model);
mKeys.add(0, key);
} else {
int previousIndex = mKeys.indexOf(previousChildName);
int nextIndex = previousIndex + 1;
if (nextIndex == mModels.size()) {
//mModels.add(model);
//mKeys.add(key);
// prepend instead append
mModels.add(0,model);
mKeys.add(0,key);
} else {
//mModels.add(nextIndex, model);
//mKeys.add(nextIndex, key);
// prepend instead append
mModels.add(previousIndex, model);
mKeys.add(previousIndex, key);
}
}
...
Here is a simple way to invert a FirebaseUI list using a RecyclerView:
boolean reverseList = true;
LinearLayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, reverseList);
if (reverseList) {
manager.setStackFromEnd(true);
}
mRecyclerView.setLayoutManager(manager);
I'm facing some difficults when I try to use the performItemClick funcion of the ListView.
All I want to do is to perform a click programatically in the first item of the list.
How can I do that? I looked up that function in the documentation, but I didn't really understand its parameters.
I tried something like:
myListView.performItemClick(myListView.getChildAt(0), 0, myListView.getChildAt(0).getId());
But it didn't work (myListView.getChildAt(0) returns null)
Thank you in advance!
mList.performItemClick(
mList.getAdapter().getView(mActivePosition, null, null),
mActivePosition,
mList.getAdapter().getItemId(mActivePosition));
Where mActivePosition is your click position!
All the best! :)
This worked for me.
listView.performItemClick(
listView.getAdapter().getView(position, null, null), position, position);
use the adapter to get the view for the position of the item. The other 2 parameters I didn't want so I left them null. Leaving convertView null causes the adapter to render a new view. It's a performance issue but since this is only happening once in a while it wont have much effect. I don't need to specify the parent for anything because I'm not using it.
position is just the spot where your item is located.
Additionally these 2 lines of code before your performItemClick create the illusion of having the list item selected. They also ensure the appropriate item is on the screen.
listView.requestFocusFromTouch();
listView.setSelection(position);
This works best for me. Run this on the main thread.
new Handler().post(new Runnable() {
#Override
public void run() {
mList.performItemClick(
mList.getChildAt(mActivePosition),
mActivePosition,
mList.getAdapter().getItemId(mActivePosition));
}
});
This is similar to Arun Jose's answer, but it will queue a message to the main thread to give the ListView some time to initiate.
I tried the code below and it worked.
getListView().performItemClick(null, 0, getListAdapter().getItemId(0));
The first parameter (view) can be null.
I went with
listView.getAdapter().getView(position, null, null).performClick();
When using Listview (simple array adapter or custom adapter) define listview and other finally make perform click.
For example:
//At onCreate function:
lv = (ListView) findViewById(R.id.listView);
lv.setAdapter(new CustomAdapter(List_item.this, list, images));
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// on click function works
}
}
int position = 0;
lv.performItemClick(lv.getAdapter().getView(position, null, null), position, lv.getAdapter().getItemId(position));
Note: After creating the setOnItemClickListener only you should call
perform click. Otherwise, it will not correctly.
this may be old but this may help :
lvList.performItemClick(null, index, lvList.getItemIdAtPosition(index) );
NOTE : the first param is null and will still work, if you have a custom adapter, convertView will be filled with custom layout and view and such.
-cheers / happy codings.
mList.performItemClick(
mList.getChildAt(mActivePosition),
mActivePosition,
mList.getAdapter().getItemId(mActivePosition));
where mActivePosition is the position of the child view in List View.
Using the code #sulal proposed, you may place it in onLoadFinished, if you use a LoaderManager. Eg something like
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
//....
// mSelectedId keeps the currently selected id
// INVID is an invalid value
if (mSelectedId == INVID) { // nothing selected
// sulal's code
new Handler().post(new Runnable() {
#Override
public void run() {
mList.performItemClick(
mList.getChildAt(mActivePosition),
mActivePosition,
mList.getAdapter().getItemId(mActivePosition));
mSelectedId = mList.getAdapter().getItemId(mActivePosition);
}
});
}
mActivePosition may be 0 (ie position on the first item) or a position kept during eg onPause
At Firstly I tried to use this code in my Fragment(Master/Detail -> NameListFragment)
getListView().performItemClick(null, 0, getListView().getAdapter().getItemId(0));
But it didn't work. When I did #Override onStart() method in fragment and I moved my code to onStart(). After that it works properly for me.
If you are working on a unit test case.
Try to use getInstrumentation().waitForIdleSync(), to wait the list be loaded, and extend the ActivityInstrumentationTestCase2
See this answer.
I just meet this freak problem today , and I try me best to deal with it.
My condition is , when I first init the layout , I need make some item checked.
But when I use gridView.getChildAt(position) , always return null. I met this problem before , caused by Not finishing drawing layout . So I send a post message . handler.postDelayed( .. , ..) , It works. Thanks who motion this Exception.
This work for me
If you would get weird result when using getView, this is because the list item you want does not exist within visible parts. Use below:
private View getViewFromAdapterByPosition(int position, ListView listView)
{
View view;
int firstVisiblePos = listView.getFirstVisiblePosition();
int lastVisiblePos = listView.getLastVisiblePosition();
if (position < firstVisiblePos || position > lastVisiblePos) {
view = listView.getAdapter().getView(position, null, listView);
} else {
view = listView.getChildAt(position - firstVisiblePos);
}
return view;
}
And then,
listView.performItemClick(getViewFromAdapterByPosition(index, listView), index, 0);
Try this one:
public static boolean performClicKOnLisViewFromIndex(ListView listView, int index){
if(listView != null){
if(listView.getAdapter()!= null && listView.getAdapter().getCount() >0 && listView.getAdapter().getCount() > index ){
listView.performItemClick(
listView.getAdapter().getView(index, null, null),
index, listView.getItemIdAtPosition(index));
return true;
}
}
return false;
}
myListView.getChildAt(0) returns null because used this very soon.
use a delay for it.
or use below code:
private class MyAdapter extends BaseAdapter
{
private final Context context;
private HashMap<Integer, View> views;
public MyAdapter(Context context)
{
this.context = context;
views = new HashMap<>();
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if(convertView == null)
{
if(views.get(position) == null)
{
final LayoutInflater layoutInflater = LayoutInflater.from(context);
convertView = layoutInflater.inflate(R.layout.my_grid, null, false);
views.put(position, convertView);
}
else
convertView = views.get(position);
}
TextView tv = convertView.findViewById(R.id.langView);
tv.setText(languageList.get(position));
return convertView;
}
}
and
adapter = new MyAdapter(getActivity());
myListView.setAdapter(adapter);
Runnable r = new Runnable()
{
#Override
public void run()
{
myListView.performItemClick(adapter.getView(position, null, myListView), position, 0);
}
};
myListView.postDelayed(r, 100);
just should use performItemClick() and it's okay.
listView.performItemClick(listView.getAdapter().getView(listView.getSelectedItemId, null, null), listView.getSelectedItemId, listView.getAdapter().getItemId(listView.getSelectedItemId));
In my case, none of the options solved my problem, so I made an adaptation in my CursorAdapter class.
I defined a global variable in the scope, so I just call the class changing this value and check the cursor position by passing the position value
mProductsAdapter.currentPosition = requiredPosition
in my ProductsAdapter builder
var currentPosition = 0
in bindView I do the check
if (cursor.position == currentPosition) {
// perform action
}
The performClick is probably called before listview was filled, put breakpoint in getView and on performItemClick and check wich is called first
getListView().performItemClick(null, 0, 0) did the trick for me (for position 0).
Dropping Some Experience.
using listview1.performItemClick, will also trigger your listview1.OnItemClickListener if you are using the listener with same listview in your code.
Hope It helps
If you would get weird result when using getView, this is because the list item you want does not exist within visible parts. Use below:
private View getViewFromAdapterByPosition(int position, ListView listView)
{
View view;
int firstVisiblePos = listView.getFirstVisiblePosition();
int lastVisiblePos = listView.getLastVisiblePosition();
if (position < firstVisiblePos || position > lastVisiblePos) {
view = listView.getAdapter().getView(position, null, listView);
} else {
view = listView.getChildAt(position - firstVisiblePos);
}
return view;
}
And then,
listView.performItemClick(getViewFromAdapterByPosition(index, listView), index, 0);
This works for me:
listview.getSelectedView().performClick();
This worked for me:
listView.getAdapter().getView(1, null, null).performClick();
This is from Begining Android Games. It creates a simple list of items which you can click to open a new activity. Each list item of course, would have to also be added to the AndroidManifest.xml as a separate activity with a .ListItem# name.
public class MainActivity extends ListActivity {
String tests[] = { "ListItem1",
"ListItem2",
"ListItem3",
"ListItem4"};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, tests));
}
#Override
protected void onListItemClick(ListView list, View view, int position, long id) {
super.onListItemClick(list, view, position, id);
String testName = tests[position];
try {
Class<?> classInstance = Class.forName("your.package.name." + testName);
Intent intent = new Intent(this, classInstance);
startActivity(intent);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
The app has a ListView with multiple-selection enabled, in the UI it works as expected. But when I read the values out using this code:
Log.i(TAG,"Entered SearchActivity.saveCategoryChoice()");
SparseBooleanArray checkedPositions = categorySelector.getCheckedItemPositions();
Log.i(TAG,"checkedPositions: " + checkedPositions.size());
if (checkedPositions != null) {
int count = categoriesAdapter.getCount();
for ( int i=0;i<count;i++) {
Log.i(TAG,"Selected items: " + checkedPositions.get(i));
}
}
I get this output, no matter what state each checkbox is in:
Entered SearchActivity.saveCategoryChoice()
checkedPositions: 0
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
Selected items: false
The SparseBooleanArray seems to return false for any non-existent item, so the source of the problems seems to be that getCheckedItemPositions() is returning an empty array. The method is behaving as if there are no items in the ListView, but there are.
I can see from the docs that no values are returned when the ListView is not set up as multi-select, but it is, using this statement:
categorySelector.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
In my scenario, the adapter I'm using is a subclass of ArrayAdapter, and (without any solid evidence) I suspect this may be the cause, though I can't see why it shouldn't work.
kcoppock is right, you need to use valueAt(), the working code should be
SparseBooleanArray checkedItems = categorySelector.getCheckedItemPositions();
if (checkedItems != null) {
for (int i=0; i<checkedItems.size(); i++) {
if (checkedItems.valueAt(i)) {
String item = categorySelector.getAdapter().getItem(
checkedItems.keyAt(i)).toString();
Log.i(TAG,item + " was selected");
}
}
}
I remember having an issue with this myself a while back. Here is my previous question, which isn't directly related to your issue, but contains some code that may help. What you might want to try is using checkedPositions.valueAt(int index) rather than checkedPositions.get(int index). I think that may be what you're actually looking for.
I still do not know why, but in my scenario, getCheckedItemPositions() returns false values for all items. I cannot see a way to use the methods on the ListView to get the boolean values out. The SparseBooleanArray object seems to have no real-world data in it. I suspect this may be because of some quirk of my implementation, perhaps that I've subclassed ArrayAdapter. It's frustrating, issues like this are a real time-drain.
Anyway, the solution I have used is to to attach a handler to each Checkbox individually as ListView rows are created. So from ListView.getView() I call this method:
private void addClickHandlerToCheckBox(CheckBox checkbox) {
checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
CheckBox checkbox = (CheckBox)arg0;
boolean isChecked = checkbox.isChecked();
// Store the boolean value somewhere durable
}
});
}
None of the above solutions have worked for me, instead I get every child (a checkedTextView) from the ListView and see if it is checked or not:
ListView myListView = myViewActivity.getListView();
ArrayList<String> selectedChildren2 = new ArrayList<String>();
for(int i = 0;i<myListView.getChildCount();i++)
{
CheckedTextView c = (CheckedTextView) myListView.getChildAt(i);
if(c.isChecked())
{
String child = c.getText().toString();
selectedChildren.add(child);
}
}
It happens if you do not choose the correct resource for showing your different items. It works fine if you choose the built-in resource android.R.layout.simple_list_item_multiple_choice. The method getCheckedItemPositions is coupled in some way to the built-in resource.
There is no need to handle the checking/unchecking of items within the ListView. It already does it on its own.
What does not seem documented is that the ListView will only do this if:
a ListAdapter is set and
the choice mode is CHOICE_MODE_MULTIPLE and
the ids used by the ListAdapter are stable.
The third point was what drove me crazy for a while.
I am not sure what 'stable' means (I guess that the ids don't ever change while the list is displayed).
As far as the ListView is concerned, it means that the method hasStableIds() in ListAdapter returns true.
I created a simple subclass of ArrayAdapter like this:
public class StableArrayAdapter<T> extends ArrayAdapter<T> {
public StableArrayAdapter(Context context, int textViewResourceId, List<T> objects) {
super(context, textViewResourceId, objects);
}
#Override
public boolean hasStableIds() {
return true;
}
}
(You already have your subclass, so just add the hasStableIds override)
Of course, one needs to add the constructor that one was using with ArrayAdapter.
Once you use this class as your ListAdapter, getCheckedItemPositions() behaves as expected.
One last note: setChoiceMode must be called AFTER setting the list adapter.
This is an old thread but since this basically came up first in current Google search here's a quick way to understand what listView.getCheckedItemPositions() does:
Unless the list Item wasn't 'toggled' at all in your ListView, it wont be added to the SparseBooleanArray that is returned by listView.getCheckedItemPositions()
But then, you really don't want your users to click every list item to "properly" add it to the returned SparseBooleanArray right?
Hence you need to combine the usage of valueAt() AND keyAt() of the SparseBooleanArray for this.
SparseBooleanArray checkedArray = listView.getCheckedItemPositions();
ArrayList<DataEntry> entries = baseAdapter.getBackingArray(); //point this to the array of your custom adapter
if (checkedArray != null)
{
for(int i = 0; i < checkedArray.size(); i++)
{
if(checkedArray.valueAt(i)) //valueAt() gets the boolean
entries.yourMethodAtIndex(checkedArray.keyAt(i)); //keyAt() gets the key
}
}
This adjustment fixed it for me.
Change the getView method so that "int position" is "final int position".
Then do this with your checkbox:
((CheckBox) convertView).setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
list.setItemChecked(position, ((CheckBox) buttonView).isChecked());
}
});
Let me elaborate.
list is a reference to the listview and in my case the adapter is an inner class in the dialog holding the list.
I found this thread by having the same problem but I think I have come up with a workaround that worked for me for unkown reasons. Whenever I tried getting a value I got nothing but if I loop through the list setting all to false it started working just like intended.
This was actually a feature I had implemented where the user could either "Select All" or "Unselect All". I run this method in my onCreate.
private void selectNone() {
ListView lv = getListView();
for (int i = 0; i < lv.getCount(); i++) {
lv.setItemChecked(i, false);
}
}
Now all my values are correct. For getting the values, in my case, just Strings.
private void importSelected() {
ListView lv = getListView();
SparseBooleanArray selectedItems = lv.getCheckedItemPositions();
for (int i = 0; i < selectedItems.size(); i++) {
if (selectedItems.get(i)) {
String item = lv.getAdapter().getItem(selectedItems.keyAt(i)).toString();
}
}
selectNone(); //Reset
}
I hope this helps someone.
I too used the solution gyller suggests that involves "initiating" the listview
ListView lv = getListView();
for (int i = 0; i < lv.getCount(); i++) {
lv.setItemChecked(i, false);
}
before calling getCheckItemPositions(), and it stopped producing erroneous results!
while I do not believe I have tried every variation described here, here is the one that has worked for me :)
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
CheckedTextView retView = (CheckedTextView) convertView;
...
retView.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
CheckedTextView chkVw = (CheckedTextView) v;
// chkVw.toggle();
// chkVw.setChecked(!chkVw.isChecked());
mLstVwWordingSets.setItemChecked(position + 1, !chkVw.isChecked());
}
});
...
}
And later
SparseBooleanArray checkedItemsArray = mLstVwWordingSets.getCheckedItemPositions();
for (int i = 1; i < mLstVwWordingSets.getCount(); i++) //skip the header view
{
if (checkedItemsArray.get(i, false))
Log.d(_TAG, "checked item: " + i);
}
I am accessing position + 1 due to a header view that my list has in place.
HTH
ArrayList<Integer> ar_CheckedList = new ArrayList<Integer>();
for each holer of check box i am using to store it in array
holder.chk_Allow.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked)
ar_CheckedList.add(position);
}
});
on click of button
for (int i = 0; i < ar_CheckedList.size(); i++)
{
HashMap<String, String> temp=(HashMap<String, String>) contactList.get(ar_CheckedList.get(i));
str_Phone_No=temp.get(TAG_CONTACT_MOBILE);
send(str_Phone_No);
}
Isn't there a rather fundamental difference between 'selected' and 'checked'?
Suspect you want to setItemChecked() from an OnItemSelectedListener...
simply go to the xml where your listview is defined and set property
**android:choiceMode="multipleChoice"**
my xmlfile
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.ali.myapplication.MainActivity">
<ListView
android:id="#+id/lvCustomList"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:choiceMode="multipleChoice"
/>
</android.support.constraint.ConstraintLayout>
and then in your javafile as:-
SparseBooleanArray checked=lvDetail.getCheckedItemPositions();
for (int i = 0; i < lvDetail.getAdapter().getCount(); i++) {
if (checked.get(i)) {
Toast.makeText(getApplicationContext(),checked.get(i),Toast.LENGTH_SHORT).show();
}
}
ArrayList<String> selectedChildren = new ArrayList<String>();
for(int i = 0;i<list.getChildCount();i++)
{
CheckBox c = (CheckBox) list.getChildAt(i);
if(c.isChecked())
{
String child = c.getText().toString();
selectedChildren.add(child);
}
}
Log.i(TAG, "onClick: " + selectedChildren.size());