My custom listView with Checkboxes and imageViews Strange Behaviour - android

I had a ListView with images that are loading by using ImageLoader(framework) and checkbox for each image.I had a adapter that is extending BaseAdapter for this ListView,when i'm checking one of the checkbox and scrolling it then i see other checkboxes which are automatically checked. Is there any way to resolve my issue. Please someone give me a clue or example.

This is because the rows are being re-used, so you need to set some attribute for each row telling it whether that row is checked or not. And then make "if and else" statement in your getView() to look if that row is checked or not, and if it is just check it, otherwise leave it unchecked.

I would suggest you use an array of booleans where you keep your checked state for every position in the list. ListView recreates list elements on scroll, so your checks could be messed up. This means that you have to check if boolean value for position of the element you're instantiating is true and then use checkBox.setChecked(true), or checkBox.setChecked(false).

Simple,
Set<String> bs = new HashSet(String);
String[] bid;
And write this in you getView method, Take it as a template. Not as a solution
public View getView(final int position, View convertView, ViewGroup arg2) {
row = convertView;
if (row == null)
{
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = vi.inflate(R.layout.your_listview,null);
}
check = (CheckBox) row.findViewById(R.id.your_checkboxid);
check.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked)
{
bs.add(bid[position]);
}
else
{
if(bs.contains(bid[position]))
{
bs.remove(bid[position]);
}
}
}
});
if(bs.contains(bid[position]))
{
check.setChecked(true);
}
else
{
check.setChecked(false);
}
return row;
}

Related

CheckBox Checked or UnChecked When Scrolling Listview in Android

I created a Listview with Textview and Checkbox. Firstly I keep all item is Checked default.
But when I uncheck the checkbox and scroll it down to uncheck some other items in the list view, the older ones are checked. Please help me with my code.
This is my code for Adapter Class.
#Override
public View getView(final int position, View convertView, ViewGroup arg2) {
try {
ViewHolder holder = new ViewHolder();
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
if (convertView == null) {
convertView = layout_inflater.inflate(R.layout.dashbordmenu_listadapter, null);
holder.txtMenutitle = (TextView) convertView.findViewById(R.id.txtPersonList);
holder.checkAppList = (CheckBox) convertView.findViewById(R.id.checkPersonList);
convertView.setTag(holder);
convertView.setTag(R.id.txtPersonList, holder.txtMenutitle);
convertView.setTag(R.id.checkPersonList, holder.checkAppList);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.checkAppList.setTag(position);
holder.txtMenutitle.setText(arrayListDashboard1.get(position).getMenuTitle());
holder.checkAppList.setChecked(arrayListDashboard1.get(position).isSelected());
holder.checkAppList.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int selectPosition = (int) buttonView.getTag();
if(buttonView.isChecked())
{
selectedAppId = arrayListDashboard1.get(selectPosition).getMenuId();
Log.d("TEST","selectedAppId = "+selectedAppId);
} else {
notSelectedAppId = arrayListDashboard1.get(selectPosition).getMenuId();
Log.d("TEST","notSelectedAppId = "+notSelectedAppId);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}
public class ViewHolder {
TextView txtMenutitle;
public CheckBox checkAppList;
}
First Method:
Add a boolean field to your model. set it as default true. if checkbox unchecked make the boolean field as false. update your checkbox according to the boolean field.
Second Method:
using SparseBooleanArray, In your adapter initialize SparseBooleanArray. It will hold the positon and boolean value. So you can keep your check box value.
SparseBooleanArray Document:
Unlike a normal array of booleans, there can be gaps in the indices.
It is intended to be more memory efficient than using a HashMap to map
Integers to Booleans, both because it avoids auto-boxing keys and
values and its data structure doesn't rely on an extra entry object
for each mapping.
Third Method:
As LunarWatcher Said, Simply Initialize ArrayList of Booleans and update your check boxes.
In you model take one Boolean to keep record of check box whether its checked or not and use it while binding views
RecylerView re-uses views while scrolling so you'll have to main the state of the checkbox for each list item. In BindViewHolder you'll check the state for the position and set the state of the checkbox accordingly.
Set a boolean variable 'isCheck' to your model class and set it as default false.change this according to checkbox value changed as true or false.
and also check in checkbox change event isCheck is true or false.

Custom List View with checkbox, selects other child elements which are not visible

I have a custom list view with custom array adapter. I am using list view for multi rows selection. But when I select the rows of visible children, and scroll up/down the list view, other child which appear they are also selected.
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(convertView == null)
convertView = layoutInflater.inflate(R.layout.addbill_row,parent,false);
initUI(convertView);
assignValues(position);
cbAddBillSelected.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
if(isChecked)
{
Data.arrlstSelectedUsers.get(position).isChecked = true;
}
else
{
Data.arrlstSelectedUsers.get(position).isChecked = false;
}
}
});
return convertView;
}
Attaching screen shots also. No idea why this is happening , I have another work around by saving selected item in shared preferences, but its a long solution.
Looking for a better solution.
why dont you use built-in ListView with Checkbox layout? android.R.layout.simple_list_item_multiple_choice will work for you.
It is something in the assign values function. you must also assign the check box in it. If this not enough as an answer plz modify your question and include the assign values function code to it. I will modify it.
This happen when convertView is not null. it gets you a used view. that's how this method work "getView". so you must modify every ui element everytime when convertView is not null.
Followed Vogella List View tutorial, and it worked like a charm. Using Tags.
Vogella List View

Android: Give every checkbox in the listview a listener without overwriting the others

Because my listView/List items have checkboxes I have the problem, that checkboxes are checked or unchecked when I'm scrolling through the list. Therefore I need to track checked items in a ArrayList for example. So I added an OnCheckedChangeListener on each checkbox and I've added the listener in the "getView" from the custom adapter for the listview.
Now since every checbox react on the click I have the following problem.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
...
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
if (!MainActivity.getSharedInstance().getIsCheckedArray().contains(tasks.get(MainActivity.ID)))
MainActivity.getSharedInstance().getIsCheckedArray().add(tasks.get(MainActivity.ID));
for (String i : MainActivity.getSharedInstance().getIsCheckedArray()) {
Log.i("RUN", i);
}
} else {
if (MainActivity.getSharedInstance().getIsCheckedArray().contains(tasks.get(MainActivity.ID)))
MainActivity.getSharedInstance().getIsCheckedArray().remove(tasks.get(MainActivity.ID));
for (String i : MainActivity.getSharedInstance().getIsCheckedArray()) {
Log.i("RUN", i);
}
}
}
});
From each list item I have an own ID and I can reach the item with that ID. But when I click on the checkboxes to get the ID, I only get the ID of one item ( the last item ). When I click on the other checkboxes they react to the change but I only get the ID from the last item and not from the items before the last one.
Do I overwrite the listeners when I always create the new Listener?
Update:
Nevermind, I added this to the onCheckChangeListener
String curIndex = tasks.get(MainActivity.ID);
and it worked
I Think your mistake is, that You doesn´t use a LayoutInflater. Just try:
LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.yourListViewItemLayout, parent,false);
final Checkbox yourCheckBox = (CheckBox)view.findViewById(R.id.yourCheckBoxId);
yourCheckBox.setOnCheckedChangeListener......
this should work

Android listview with checkbox problem

I have a weird problem! I'm trying to create a listview with checkboxes. In my other thread I was told that I should use an array that keeps track of the rows that are checked. I did that and it worked fine-ish but the logic is wrong and I run into another problem now.
public View getView(final 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.row, null);
}
CheckBox checkbox = (CheckBox)v.findViewById(R.id.checkbox);
checkbox.setChecked(checked[position]);
final LinearLayout rowLayout = (LinearLayout) v.findViewById(R.id.individualRow);
checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked)
{
rowLayout.setBackgroundColor(Color.GRAY);
checked[position] = false;
}
else
{
rowLayout.setBackgroundColor(Color.DKGRAY);
checked[position] = true;
}
}
});
}
Having all the checkboxes unchecked initially it works fine it keeps the ones that i select checked even if I scroll down and back up again but the checked array is not properly set up. Basically the if test should be the other way arround!
if(isChecked)
{
rowLayout.setBackgroundColor(Color.GRAY);
checked[position] = true;
}
else
{
rowLayout.setBackgroundColor(Color.DKGRAY);
checked[position] = false;
}
The problem is with the scroll really because every time I scroll the onCheckedChanged method is called and since its recycling the rows it passes in the position of the new row that its not selected but since it has the same index as the one that was previously selected it changes its value. for example if I check the box with index 2 (set it to true) and then scroll down a new row becomes row with index 2, the method is called again and it unsets the checkbox(the field in the checked array).
I need it to "remember" all the boxes that are checked. In other words I want the checked array to be initialised properly. And also to remember which boxes are checked and not lose them everytime I scroll!
What am I doing wrong?
Can you please help me?
Thanks in advance -- Mike
This was tricky.
The problem is that you are calling setChecked, activating the old OnCheckedChangeListener.
The fix is quite simple: call setOnCheckedChangeListener before calling setChecked. This way you sever the link to the old listener from the recycled view.
Check this for Single selection of Checkbox in Listview
AdpList adapter=new AdpList(this,array,false);
listview.setAdapter(adapter);
When you select any Item then on item CLickListener do as Follows
listview.setonItemClickListener(new OnItemClickListener)
Here You will Get the Position of the Current Item
array.get(Position);
Get the Checkbox view and On clicking the Checkbox, create a method in Adapter, Like
adapter.setList(true);
adapter.notifyDataSetChanged();
And In Adapter check the Parameter that I have Passed in the Setlist method
then put condition:
if (isChecking==true)
{
checkbox1.setChecked(true);
}else{
checkBox1.setChecked(false);
}

Custom listview with checkbox problem

I'm trying to create a custom list which will have checkboxes that allow you to select several items from the list.
The list with the checkboxes is displayed ok but if i check a checkbox and then scroll other items further down the list are also checked.
Its basically the same problem as here
I understand that it has something to do with the way android recycles the view but I cant see how to fix this! Can somebody help me???
Thanks -- Mike
You need a data structure to keep track of which rows are checked. This could be as simple as a bool[] checked.
In your getView, make sure that you set the checkbox state to the contents of checked[position]. You should also set an OnCheckedChangedListener on your check boxes in getView so that they update your data with checked[position] = isChecked.
Yes, the rows in a ListView are recycled, so make sure to populate all the appropriate data for a row before you leave getView.
You could try implementing OnClickListener for checkbox instead of OnCheckChangedListener. It worked for me.
Create an ArrayList<Integer>. add a OnCheckChangedListener to your checkbox. Inside the changed method, add or remove the list view position to the ArrayList<Integer>.
in your getView method, check to see if the ArrayList<Integer> contains the current list view position. if it contains the position, set checked to true, otherwise false.
every time you click a checkbox, either add or remove the Integer from the ArrayList.
Check the code below -
public View getView(int position, View convertView, ViewGroup parent){
View view = convertView;
ViewHolder holder = new ViewHolder();
if(view == null){
view = inflater.inflate(R.layout.list_callcycle_blue, null);
holder.llContainer = (LinearLayout) view.findViewById(R.id.ll_container);
holder.lblLabel = (TextView) view.findViewById(R.id.txt_desc);
holder.cb = (CheckBox) view.findViewById(R.id.cb_store);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
final Object data = getItem(position);
holder.lblLabel.setText(data.getDescription());
holder.cb.setTag(position);
holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int position = (Integer) buttonView.getTag();
objects.get(position).setChecked(buttonView.isChecked());
}
});
holder.cb.setChecked(isChecked(position));
return view;
}
Always keep in mind, use change holder.cb.setOnCheckedChangeListener() i.e. any listener before it's setting data, in our case it is holder.cb.setChecked()
Reason : When we scroll, listview will recycle the views, so if setchecked is used before listeners then it will pick values on the basis of old listener. And if we set it after listener, then it will take latest values
EDITED PART
Below part will show how isChecked() and setChecked() methods used for retrieving checked data
/*
* This function is in your Custom Adapter Class
*/
private boolean isChecked(int position){
return object(position).isChecked();
}
/**
* Getter Setter Class / Data Model Class that defines your object
*/
private class MyObject{
private boolean isChecked;
private String a, b, c, orWhateverYourObjectNeeds;
public void setChecked(boolean isChecked){
this.isChecked = isChecked;
}
public boolean isChecked(){
return isChecked
}
}

Categories

Resources