Getting Checkboxes in a custom ListView to work properly - android

what i do have is a custom row layout for my listview:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="#+id/chkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
I am using this layout for my adapter in the activity:
adapter = new AdapterCustomBoxes(context, R.layout.custom_check_row, (ArrayList<Map<String, String>>) list_values);
list.setAdapter(adapter);
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
And an adapter for that, here is the getView method of my adapter:
public class AdapterCustomBoxes extends ArrayAdapter<Map<String, String>> {
private List<Map<String, String>> list;
private List<Map<String, String>> orig_list;
private Context upper_context;
private View view;
public AdapterCustomBoxes(Context context, int textViewResourceId, ArrayList<Map<String, String>> items) {
super(context, textViewResourceId, items);
this.list = items;
this.orig_list = items;
this.upper_context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
view = convertView;
if (view == null) {
LayoutInflater vi = (LayoutInflater)upper_context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(R.layout.custom_check_row, null);
}
Map<String, String> selectedgroup = new HashMap<String, String>();
selectedgroup = (Map<String, String>) list.get(position);
String itemtext = (String) selectedgroup.get("item_text");
TextView row_text = (TextView) view.findViewById(R.id.text);
row_text.setText(itemtext);
return view;
}
}
And now here comes the point where i get confused. When i check one of those checkboxes the clicked one gets checked. But without any logic somes of the other line's checkboxes also get checked. And if i then scroll the list the checked status of each box may change from one time i come across this line to the next time.
So what is the problem here?
I already tried to do add an onclicklistener to the view in the adapter and then set the explicit checkbox to cheched/unchecked when this listener is triggered but this also does not work as i expected, i clicked on the one box and the other one got checked.
So i guess this is a problem with recycled views? Do i have to store the checked Status seperately and restore it every time in the getView method could this be a solution? Or is there an easier way? Please help ;)
So can anybody give me a hint? Thnaks a lot!
--- EDIT ---
So what i now tried to save the status of the checkboxes was to creat a map:
private Map<View, Boolean> itm = new HashMap<View, Boolean>();
and save the status when a box is clicked in in the getView method:
CheckBox chkbox = (CheckBox) view.findViewById(R.id.chkbox);
chkbox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
itm.put(buttonView, isChecked);
}
});
if(itm.containsKey(chkbox)){
iteminfo_row_chkbox.setChecked( itm.get(chkbox) );
}else{
iteminfo_row_chkbox.setChecked(false);
}
Sorry if this is the completely wrong approach in any way but shouldn't this work? The result is the same that the whole list and checked statuses are not correct, what am i doing wrong?

A few off-topic comments:
First you don't need this:
Map<String, String> selectedgroup = new HashMap<String, String>();
You can just do this:
Map<String, String> selectedgroup = (Map<String, String>) list.get(position);
Also, are you sure you need the TextView? The checkbox can hold text too.
About your problems, how do you save which checkbox is checked? You should set the checkbox when returning the view, specially when reusing views.
-- Edit --
Why don't you create a private class like this?
private class ListItem{
String text;
boolean value;
}
And then instead of a List<Map<String,String>> you could just have a List<ListItem>.
About the onCheckedChangeListener, you could iterate of the list using the text from the checkbox to find the correct position and then change the value. If the text is not unique,
instead of using onCheckedChangeListener, you could use on the ListView a OnItemClickListener which holds the position of the click.

Okay i think i got it, i used a static id value from the selectedgroup map as the key in the itm map to find the checked/unchecked status of the checkbox. Using the view was the wrong approach because they can't be used as the key.

Related

How to Disable the 2nd Spinner Item Which is selected Already in 1st Spinner in Android

I want to Convert the Languages. So i am using two Spinners one is "From Language" and Another one is for "To Language". If One Language is Selected in "From Language" Spinner, it shouldn't display (or it should be disabled) in 2nd spinner. how can i achieve it?
Ex. if i Select English in 1st Spinner, 2nd Spinner Shouldn't display English in its dropdown.
This is may not be the best way try this.
ArrayList<String> languages = new ArrayList<>();
languages.add("English");
languages.add("Hindi");
languages.add("Telugu");
languages.add("Tamil");
languages.add("Kannada");
languages.add("Malayalam");
// make a array list of languages
String option1 = null;
Spinner spinnerOption1 = (Spinner) findViewById(R.id.spinner1);
final ArrayAdapter<String> adapterOpton1 = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item, languages);
spinnerOption1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerOption1.setAdapter(adapterOpton1);
spinnerOption1.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
option1 = adapterOpton1.getItem(position);
}
});
int selectedIndex;
for (String item : languages) {
if (item.equals(option1)) {
selectedIndex == languages.indexOf(item);
}
}
ArrayList<String> languages2 = languages;
languages2.remove(selectedIndex);
Spinner spinnerOption2 = (Spinner) findViewById(R.id.spinner2);
final ArrayAdapter<String> adapterOption2 = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item, languages2);
spinnerOption2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerOption2.setAdapter(adapterOption2);
Explanation:
lets create a arraylist with languages
bind it to the adapter on the spinner, on selection to the spinner one keep a track of that selection, then find the index of the selection in the arraylist.
create second arraylist with the same languages and find and remove the user selected item, create an adapter and bind the data.
Hope it helps.
Use Hashmaps it will be easier. Create an Adapter that uses Key Values for populating adapter.
This is a snippet I found from another link on how to do that, in case you are not familiar
public class HashMapAdapter extends BaseAdapter {
private HashMap<String, String> mData = new HashMap<String, String>();
private String[] mKeys;
public HashMapAdapter(HashMap<String, String> data){
mData = data;
mKeys = mData.keySet().toArray(new String[data.size()]);
}
#Override
public int getCount() {
return mData.size();
}
#Override
public Object getItem(int position) {
return mData.get(mKeys[position]);
}
#Override
public long getItemId(int arg0) {
return arg0;
}
#Override
public View getView(int pos, View convertView, ViewGroup parent) {
String key = mKeys[pos];
String Value = getItem(pos).toString();
//do your view stuff here
return convertView;
}
}
Credit What adapter shall I use to use HashMap in a ListView
Now for your management of the adapters.
LanguageOneMap.put (all your keys 0-whatever) value (english-whatever)
LanguageTwoMap.put (same as above)
LanguageAllMap.put (same as above)
Adapter 1 selects Language Callback(languageSelectedFromOneKey){
LanguageTwoMap.clearAll
LanguageTwoMap.put (all again)
LanguageTwoMap.remove(languageSelectedFromOneKey)
LanguageTwoAdapter.notifyDataSetChanged()
}
The above is just pseudo code meant to give the idea, not exact copy and paste. Hope that is enough to get you going. There are many ways to skin this cat, you could even use the same list for both adapters. Then when one is selected from one or the other, set a property of "selectedOtherLanguage" in the opposite adapter, then in the GetView method if data.get(pos) == selectedFromOtherListItem return, don't draw.
Many ways to do this, just a matter of how you want to do it. Goodluck.

Create list view with custom set of data in android?

I am trying to create ListView with custom data set as follows:
String superType = "random1";
String superTypea = "random12";
String superType12 = "random2";
String superType_amount = "child1";
String childtype_calulated = "2323";
String superType_amount = "child2";
String childtype_calulated = "23223";
String superType_amount = "child2";
String childtype_calulated = "amount3";
Now I want to create ListView with this set of data how to do that?
Here is the list structure...
row1=superType |superType_amount |childtype_calulated
row2=superTypea |superType_amount |childtype_calulated
row3=superType12|superType_amount |childtype_calulated
Is there any solution of this?
It is absolutely possible to do this. First, I would recommend putting your data into a collection. It would be preferable to put them into an object and then a collection of those objects. From there you can add a ListView to your main layout, define a custom layout for your list items, and populate your ListView using an ArrayAdapter.
Here is a really good example of how you can do this well. It includes examples of loading data from an external source, which you don't need.
However, if you're getting into development now I would suggest you look into RecyclerView as well. RecyclerView is new and included in the AppCompat v7 library for use on pre-Lollipop Android. A RecyclerView will be a little more complicated to implement for a simple list but is significantly more scalable and efficient. I believe it is Google's intention to replace ListView with RecyclerView entirely in the future.
Here is a pretty simple introduction to making a list with RecyclerView.
EDIT
Using an ArrayAdapter with a ListView. First you need to create a model to store your data, some kind of class that you can put into a collection, for example:
public class Item {
public String title;
public String sub1;
public String sub2;
public void Item(String t, String s1, String s2) {
title = t;
sub1 = s1;
sub2 = s2;
}
}
Then you need to define the layout for the item in your list:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/sub1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/sub2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Then in you need to make your custom ArrayAdapter by extending the ArrayAdapter class:
public class ItemAdapter extends ArrayAdapter<Item> {
public ItemAdapter(Context context, ArrayList<Item> items) {
super(context, 0, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Item item = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_layout, parent, false);
}
TextView title = (TextView) convertView.findViewById(R.id.title);
TextView sub1 = (TextView) convertView.findViewById(R.id.sub1);
TextView sub2 = (TextView) convertView.findViewById(R.id.sub2);
title.setText(item.title);
sub1.setText(item.sub1);
sub2.setText(item.sub2);
return convertView;
}
}
Then all you need to do is create an instance of the adapter in your main class and attach your collection to it:
ArrayList<Item> data = new ArrayList<Item>();
ItemAdapter adapter = new ItemAdapter(this, data);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
This should populate your ListView with all the items that you need in your list. I haven't run any of this code so there might be one or two small bugs for you to fix.

Android ExpandableListView Where to Place onClickListener

I have an ExpandableListView. Each child has a CheckBox and a TextView. When a user taps a child row, the CheckBox is supposed to change its state (checked vs unchecked). This works correctly if the user taps directly on the check box. However, if the user taps on the text view (same row, immediately to the right of the check box), I get a null pointer error as soon as I try to refer to the check box. Can anyone see what is wrong?
EDIT: After reading the suggestion below, I did some investigation and realized that I can implement my clickListener inside my adapter under getChildView(). This solves my issue with the null pointer as I can easily get a reference to the child view.
However, it creates another issue that I see no elegant solution to. Each time a child is clicked, I need to make changes to the listview itself. The data for this list resides in an ArrayList whose scope is within the Activity (not in the Adapter). If my clickListener is in the Adapter, how can I call back to the Activity to make changes to the ArrayList?
This strikes me as a catch-22. If I want to be able to manipulate my data, I can't get a reference to the child view. But if I want a reference to my child view, my data is out of scope, so I can't manipulate it. How do people resolve this? I must be missing something.
I'll throw in the relevant adapter code where you can see the beginning of my attempt to add a child onClickListener.
Thanks again!
public class Settings extends Activity {
//this is the list I need to access from the adapter if my click listener is there
private ArrayList<Categories> categoriesList = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_smart_settings);
db = new EventsDB(this);
expListGroups = new ArrayList<ExpandListGroup>();
setGroups();
/* Set up the data adapter */
expAdapter = new ExpandListAdapter(Settings.this, expListGroups);
populateExpandableGroups();
}
public void setGroups() {
/* Create lists of the individual line items */
categoriesList = db.getCategoriesForClient(client);
locationsList = db.getLocationsForClient(client);
/* Add an item to the locations list to allow the user to add a new location */
locationsList.add(new ClientSmartFinderLocations(client, "Add Location", null, false));
ExpandListGroup categoryGroup = new ExpandListCategory("Choose Categories", categoriesList);
ExpandListGroup locationGroup = new ExpandListLocation("Choose Locations", locationsList);
expListGroups.add(categoryGroup);
expListGroups.add(locationGroup);
}
private void populateExpandableGroups() {
expandableList = (ExpandableListView) findViewById(R.id.expandable_list);
expandableList.setAdapter(expAdapter);
//I've removed this section and moved it to the adapter, per my edit above
// expandableList.setOnChildClickListener(new OnChildClickListener() {
//
// #Override
// public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
//
// /* Update the finder setting for this client */
// String category = categoriesList.get(childPosition).getCategory();
// Boolean isSelected = !categoriesList.get(childPosition).getIsSelected();
// db.setClientCategory(client, category, isSelected);
//
// /* Update the check box to provide feedback to the user */
// View view = parent.getChildAt(childPosition - parent.getFirstVisiblePosition() + 1);
// CheckBox checkBox = (CheckBox) view.findViewById(R.id.check_box);
//
// //error occurs here
// checkBox.setChecked(!checkBox.isChecked());
// return true;
// }
// });
expAdapter.notifyDataSetChanged();
}
public class ExpandListAdapter extends BaseExpandableListAdapter {
//other methods
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, final ViewGroup parent) {
view = getCategoryChildView(groupPosition, childPosition, view);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView tv = (TextView) v.findViewById(R.id.expand_list_item);
CheckBox checkBox = (CheckBox) v.findViewById(R.id.check_box);
String category = tv.getText().toString();
Boolean isSelected = !checkBox.isSelected();
db = new EventsDB(context);
db.setClientCategory(client, category, isSelected);
checkBox.setChecked(!checkBox.isChecked());
//here I need to do some things that require me to manipulate the categoriesList from the Activity class - but it is out of scope
}
});
return view;
}
}
<CheckBox
android:id="#+id/check_box"
android:layout_marginLeft="30dp"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/expand_list_item"
android:paddingLeft="10dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/smart_finder_settings_font_size"
android:textColor="#FFFFFF" />
I think that I have a solution. If I create an instance of the Settings activity class within the Adapter, I can add the usual getter/setter methods to the Settings class. I can then call these methods from the adapter to get at that list, modify it, and then push it back to the Settings class, and all should be well.
It's a basic OOP approach, but the mental hangup for me was the idea of instantiating an activity. I don't know if this is common or not, but it seems weird to me. Anyone have a more elegant solution?
Within the Settings class:
public ArrayList<Categories> getCategoriesList() {
return categoriesList;
}
public void setCategoriesList(ArrayList<Categories> list) {
categoriesList = list;
}
Within the adapter:
Settings settings = new Settings();
ArrayList<Categories> tempCategoriesList = new ArrayList<Categories>();
tempCategoriesList = settings.getCategoriesList();
//make changes to the list
settings.setCategoriesList(tempCategoriesList);
You should set the checkbox checked state inside your ExpandListAdapter instead of accessing the view inside the ExpandableListView directly.
Im not a pro, so take that in mind. but what about storing the data you need the clicklistener to manipulate in a gobal application class? Maybe not the most elegant, but might work.
user55410 is on the right track. In your Settings() Activity, make categoryList static, then when you change it with the getter/setter methods from the new instance you create in your it will modify all instances of Settings.categoryList.

Can't get custom ListAdapter to work

I have followed various "how to" examples to the letter (or so I thought), but I still can't get my custom ListAdapter to work. I have a dialog with a list view containing strings which are references to an array of objects (of class "Notam"). I want to set the colour of each list item according to an attribute of the referenced object.
(Before you read my code, I have a quirk that the braces must line up or I can't see where the blocks are. I don't like the convention of putting an opening brace at the end of the same line.)
This is the code for the custom class (just as a test I am trying to set the text colour of each item to magenta):
private class GotoAdapter extends ArrayAdapter<String>
{
private ArrayList<String> items;
public GotoAdapter(Context context, int textViewResourceId, ArrayList<String> items)
{
super(context, textViewResourceId, items);
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.goto_row, null);
}
String s = items.get(position);
if (s != null)
{
TextView tt = (TextView) v.findViewById(R.id.text1);
if (tt != null)
{
String s1 = (String)tt.getText(); // this is always an empty string!
tt.setTextColor(0xFF00FF); // this has no effect!
}
}
return v;
}
}
String s has the displayed text as expected (except you can't see it on the screen) when using this derived class), but the text in the returned TextView is always an empty string, and setting the colour has no effect.
This is the code that displays the dialog when a "Goto" button is clicked in my main view:
mGotoButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
// The pre-loaded array gets round a problem which I read about somewhere else
// (the ArrayList gets cleared again below)
String[] array = {"one", "two", "three"};
ArrayList<String> lst = new ArrayList<String>();
lst.addAll(Arrays.asList(array));
// custom dialog
final Dialog dialog = new Dialog(context);
dialog.setContentView(R.layout.goto_dialog);
dialog.setTitle("Choose Notam");
// Create the list view and adapter
final ListView list = (ListView) dialog.findViewById(R.id.goto_list);
// If I replace this reference to my custom adapter...
final GotoAdapter adapter = new GotoAdapter
(mContext, R.layout.goto_row, lst);
// ... with this normal one, everything works!
// (but of course now I can't get access to the objects.)
// final ArrayAdapter<String> adapter = new ArrayAdapter<String>
// (mContext, R.layout.goto_row, lst);
list.setAdapter(adapter);
// Populate the adapter
adapter.clear(); // first clear the silly preset strings
// Notam is my object class.
// Spine.mNotamsDisplayed is a public static NotamArray.
// class NotamArray extends ArrayList<Notam>
// Spine is my main activity where I keep my global (app-wide) stuff.
for (Notam notam : Spine.mNotamsDisplayed)
{
// This gets the reference string from the Notam object.
// This is what goes into the list.
String s = notam.getReference();
adapter.add(s);
}
// Sort into alphabetical order
adapter.sort(new Comparator<String>()
{
public int compare(String arg0, String arg1)
{
return arg0.compareTo(arg1);
}
});
list.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> a, View v, int pos, long id)
{
String s;
int i;
s = (String)a.getItemAtPosition(pos);
// This static function returns the index in Spine.mNotamsDisplayed
// which is referenced by the reference string s.
// I have to do this because I lost the one-for-one correlation of page
// indexes with list view entries when I did the sort.
i = NotamArray.findNotamIndexByReference(Spine.mNotamsDisplayed, s);
if (i >= 0)
{
// This is what the Goto button and dialog is all about: this
// just moves my main view's pager to the page that was selected.
mPager.setCurrentItem(i);
}
dialog.dismiss();
}
});
dialog.show();
}
});
This is my xml for the dialog (goto_dialog.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="#+id/goto_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
And this is my xml for the list view row (goto_row.xml):
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#00FF00"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceMedium"
android:padding="2dp"
android:textSize="20dp"
/>
(I set the text colour to green so I could see that this bit was working if I used the standard list view adapter. (Sure enough the text of every entry was green. However no text could be seen if I used my custom adapter, although it was there - I assume black on black.)
There must be someone out there who can spot what must be a trivial error I have made - please!
From what I read, it seems like you want to set the text color of every list item to match the color you have in your array.
I want to set the colour of each list item according to an attribute of the referenced object.
However, your initial array is set as
String[] array = {"one", "two", "three"};
So this will lead to problems later when you are dynamically setting the text color based on your array. But I'm sure you meant to change that later.
When you use a standard array adapter, it just shows the items in the array as a text, that's why:
if I used the standard list view adapter. (Sure enough the text of every entry was green. However no text could be seen if I used my custom adapter
To see if your custom adapter is working (changing color), you can just start off by adding one line to your TextView of goto_row.xml file:
android:text="Test String"
Now it will show "Test String" with different colors, and the
String s1 = (String)tt.getText();
above line will get "Test String"
I found the trivial error that I hinted at at the end of my question. It was this line in the custom adapter:
tt.setTextColor(0xFF00FF);
It seems that 0xFF00FF is not a valid colour value, which is why I saw nothing on the screen.
Changing that to:
tt.setTextColor(Color.rgb(255, 0, 255);
fixes the problem, and the default green colour is changed to magenta, and I can set the text to the value I want. So I can now set the individual row colours to what they need to be.
Thanks to #LukasKnuth and #tigerpenguin for pointing me in the right direction.

checkbox in List being checked unexpectedly

I have list of checkboxes in list binded by Custom simpleCursorAdapter.
In my custom simpleCursorAdapter, I've overridden newView and bindView with my modifications.
I've managed somehow to do multichoice.
The wierd thing is, after I delete any item from my list, the first item's checkbox is being checked all of a sudden. How does that happen? How can I solve it?
My SimpleCursorAdapter class:
public class MyListCursorAdapter extends SimpleCursorAdapter
{
private Context context;
private int layout;
public MyCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to)
{
super(context, layout, c, from, to);
this.context = context;
this.layout = layout;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
{
Cursor c = getCursor();
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
CheckBox chkBoxBtn = (CheckBox) v.findViewById (R.id.deleteTwittChkBox);
if (chkBoxBtn != null)
{
chkBoxBtn.setChecked(false);
}
return v;
}
#Override
public void bindView(View v, Context context, Cursor c)
{
--binding view to my textsview in my items
//now it's the importat part:
CheckBox chkBoxBtn = (CheckBox) v.findViewById(R.id.deleteTwittChkBox);
if (chkBoxBtn != null)
{
chkBoxBtn.setId(Integer.valueOf(c.getString(c
.getColumnIndex(MyUsers.User._ID))));
chkBoxBtn.setOnClickListener(new OnItemClickListener(chkBoxBtn, v));
chkBoxBtn.setChecked(false);
}
}
//i couldnt find another way of doing this, but this is how i set listeners to my checkboxses
static ArrayList<String> checkedItemsList = new ArrayList<String>();
private class OnItemClickListener implements OnClickListener
{
private int mPosition;
private CheckBox chkBox;
OnItemClickListener(CheckBox mChkBox, View v)
{
chkBox = mChkBox;
chkBox.setChecked(false);
}
#Override
public void onClick(View v)
{
if (chkBox.isChecked())
{
checkedItemsList.add(String.valueOf(chkBox.getId()));
}
else
{
checkedItemsList.remove(String.valueOf(chkBox.getId()));
}
}
}
}
Here is the code part from the ListActivity class which describes the button that deletes the checked box items:
OnClickListener btListener = new OnClickListener()
{
public void onClick(View view)
{
// long[] items = listView.getCheckItemIds();
int x = 0;
Uri myUri = Uri
.parse("content://com.idan.datastorageprovider/users");
String where = "_id" + "=?";
//here i am tatking all checkboxes which ive added from the adapter class
ArrayList<String> checkedItemsList = MySimpleCursorAdapter.checkedItemsList;
for (String itemID : checkedItemsList)
{
getContentResolver()
.delete(myUri, where, new String[] { itemID});
checkedItemsList.remove(itemID);
}
}
};
I doubt that SimpleCursorAdapter is the right class to extend here.
Is the "checked" state connected to the data XML in any way? No? So you need your own custom adapter!
Basically all adapters have to implement a way to generate a view from a given element (more precisely an element position!). This will be called at any time where the list wants to display an element. Now, the trick it uses is to re-use formerly created list view elements that cannot be seen on screen any more! Thus: when you scroll your list down and an element disappears at the top, EXACTLY this view object will be re-used for the next appearing item.
So, when this method is called with a given "old" view that should be re-used, all contained elements will have to be set according the elements data. If a checkbox is part of this game, you will have to have a storage for the checked state! It is not sufficient to have a checkbox as there will be less checkbox objects as there are list elements!
SimpleCursorAdapters are there to - yeah - represent SIMPLE things. An XML describing data (images and text, as the documentation states). Because of this simplicity all you have to do here is provide a method to create NEW element view objects - you are not intercepting the re-use process AT ALL! It basically only knows how to put the data into an existing view object - but it is lacking the knowledge of how to handle checked/unchecked boxes!
Your solution: write your own BaseAdapter extension and do what has to be done: implement "getView" (and some other methods like getItem, getItemId and getCount). It's not hard at all!
This API Demo uses a BaseAdapter and the mExpanded state here is basically identical to your checkbox states!
Good luck!
You might need to call notifyDataSetChanged when you modify the data.
The problem is probably that you're calling setChecked from within the onItemClickListener. One hacky way around this is to do the following before and after you call setChecked from within your listener:
chkBox.setClickable(false);
chkBox.setChecked(false);
checkBox.setClickable(true);
This will prevent your onItemClickListener from getting called when you manually call setChecked.

Categories

Resources