Reputation: 1063
What I have: a custom listview with Textviews and checkbox.
public class NewQAAdapterSelectFriends extends BaseAdapter {
private LayoutInflater mInflater;
private Person[] data;
public NewQAAdapterSelectFriends(Context context) {
mInflater = LayoutInflater.from(context);
}
public void setData(Person[] data) {
this.data = data;
}
@Override
public int getCount() {
return data.length;
}
@Override
public Object getItem(int item) {
return data[item];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_select_friends, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
viewHolder.nameText.setTag(viewHolder.nameText);
viewHolder.nameText.setTag(viewHolder.surnameText);
viewHolder.contactImage.setTag(data[position]);
viewHolder.checkBox.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
Person element = (Person) viewHolder.checkBox.getTag();
if(isChecked){
element.setCheck(buttonView.isChecked());
//data[position].setCheck(true); //this is equivalent to previous line
}
else{
//to-do
}
}
});
viewHolder.checkBox.setTag(data[position]);
} else {
}
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.nameText.setText(data[position].getName());
holder.surnameText.setText(data[position].getSurname());
holder.contactImage.setImageResource(data[position].getPhotoRes());
holder.contactImage.setScaleType(ScaleType.FIT_XY);
holder.checkBox.setChecked(data[position].isCheck());
return convertView;
}
static class ViewHolder {
TextView nameText;
TextView surnameText;
ImageView contactImage;
CheckBox checkBox;
}
}
Thanks for the answers :)
EDIT: With the suggestion i changed my getView like below:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_select_friends, null);
viewHolder=new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
viewHolder.nameText.setTag(viewHolder.nameText);
viewHolder.nameText.setTag(viewHolder.surnameText);
viewHolder.contactImage.setTag(data[position]);
viewHolder.checkBox.setChecked(data[position].isCheck());
viewHolder.checkBox.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
if(viewHolder.checkBox.isChecked()==true)
data[position].setCheck(true);
else
data[position].setCheck(false);
}
});
}
else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.nameText.setText(data[position].getName());
viewHolder.surnameText.setText(data[position].getSurname());
viewHolder.contactImage.setImageResource(data[position].getPhotoRes());
viewHolder.contactImage.setScaleType(ScaleType.FIT_XY);
viewHolder.checkBox.setChecked(data[position].isCheck());
return convertView;
}
SITUATION AFTER EDIT: Now, if i check the initial items that are shows on the screen and then I scrool the list, their value is correctly saved. But When I scroll the list and for example i want to check the last tree checkboxs of my list then after I scroll they become uncheked....BUT WHY??????
SOLVED: I solved my problem of getView with this code:
public class NewQAAdapterSelectFriends extends BaseAdapter {
private LayoutInflater mInflater;
private Person[] data;
boolean[] checkBoxState;
ViewHolder viewHolder;
public NewQAAdapterSelectFriends(Context context) {
mInflater = LayoutInflater.from(context);
}
public void setData(Person[] data) {
this.data = data;
checkBoxState=new boolean[data.length];
}
@Override
public int getCount() {
return data.length;
}
@Override
public Object getItem(int item) {
return data[item];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_select_friends, null);
viewHolder=new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
}
else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.nameText.setText(data[position].getName());
viewHolder.surnameText.setText(data[position].getSurname());
viewHolder.contactImage.setImageResource(data[position].getPhotoRes());
viewHolder.contactImage.setScaleType(ScaleType.FIT_XY);
viewHolder.checkBox.setChecked(checkBoxState[position]);
viewHolder.checkBox.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(((CheckBox)v).isChecked()){
checkBoxState[position]=true;
data[position].setCheck(true);
}else{
checkBoxState[position]=false;
data[position].setCheck(false);
}
}
});
return convertView;
}
static class ViewHolder {
TextView nameText;
TextView surnameText;
ImageView contactImage;
CheckBox checkBox;
}
}
I have seen this tutorial to do my getView: http://androidcocktail.blogspot.it/2012/04/adding-checkboxes-to-custom-listview-in.html
Upvotes: 25
Views: 15082
Reputation: 135
You need to update the adapter to retain the value of checkbox
holder.chk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CheckBox c = (CheckBox)v.findViewById(R.id.chkID);
Boolean chk = c.isChecked();
Integer pos = (Integer)v.getTag();
itemList.get(pos).setChk(chk);
}
});
For more help you can refer this post in Retain Checkbox value
Upvotes: 0
Reputation: 1855
Use setTag() in adapter. You can see example here Example listview with checkbox scroll issue
Upvotes: 0
Reputation: 413
I have a good alternative for a CheckBox. You can use android:state_activated="true"
for your ListView rows. It does not lose its state and does not require lots of code.
Here is how to works
active_row.xml
in your drawable folder
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true"
android:drawable="@android:color/darker_gray"/>
</selector>
android:background="@drawable/active_row.xml"
android:choiceMode="multipleChoice"
You can check the State of every row like this
View v;
LinearLayout yourRowLayout;
for (int i = 0; i < yourListView.getChildCount(); i++) {
v = yourListView.getChildAt(i);
yourRowLayout = (LinearLayout) v.findViewById(R.id. yourRowLayout);
if(yourRowLayout.isActivated()){.... } }
Upvotes: 0
Reputation: 61
I solved my problem just changing the "setOnCheckedChangeListener" to "setOnClickListener"
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
CheckBox cbItemChecklist = new CheckBox(context);
holder = new ViewHolder();
holder.cbItemChecklist = cbItemChecklist;
convertView = cbItemChecklist;
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final ItemChecklist itemChecklist = itensChecklist.get(position);
holder.cbItemChecklist.setText(itemChecklist
.getDescricaoItemChecklist());
holder.cbItemChecklist.setChecked(itemChecklist.isChecked());
holder.cbItemChecklist
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(itemChecklist.isChecked()){
itemChecklist.setChecked(false);
} else {
itemChecklist.setChecked(true);
}
}
});
return convertView;
}
Upvotes: 6
Reputation: 4297
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
Upvotes: 4
Reputation: 1189
check this code
public class NewQAAdapterSelectFriends extends BaseAdapter {
private LayoutInflater mInflater;
private Person[] data;
ArrayList<String> checkedItem=new ArrayList<String>();
public NewQAAdapterSelectFriends(Context context) {
mInflater = LayoutInflater.from(context);
}
public void setData(Person[] data) {
this.data = data;
}
@Override
public int getCount() {
return data.length;
}
@Override
public Object getItem(int item) {
return data[item];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_select_friends, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
convertView.setTag(viewHolder);
viewHolder.nameText.setTag(viewHolder.nameText);
viewHolder.nameText.setTag(viewHolder.surnameText);
viewHolder.contactImage.setTag(data[position]);
viewHolder.checkBox.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
Person element = (Person) viewHolder.checkBox.getTag();
if(isChecked){
getCheckList(data[position],isChecked);
}
else{
getCheckList(data[position],isChecked);
}
}
});
viewHolder.checkBox.setTag(data[position]);
}
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.nameText.setText(data[position].getName());
holder.surnameText.setText(data[position].getSurname());
holder.contactImage.setImageResource(data[position].getPhotoRes());
holder.contactImage.setScaleType(ScaleType.FIT_XY);
if(checkedItem != null && checkedItem.contains(data[position])){
viewHolder.checkBox.setChecked(true);
}else
{
viewHolder.checkBox.setChecked(false);
}
return convertView;
}
static class ViewHolder {
TextView nameText;
TextView surnameText;
ImageView contactImage;
CheckBox checkBox;
}
public void getCheckList(String value,boolean status){
if(!checkedItem.contains(value) && status)
{
checkedItem.add(value);
}
if(checkedItem.contains(value) && !status)
{
checkedItem.remove(value);
}
}
}
Upvotes: 0
Reputation:
You are setting the tag of the checkbox only if convertview is null. This happens only for the first screen of records. When user scrolls down, the previous convertviews are recycled. Thus your checkboxes have older data items as their tags.
Your checked change listener should look like this:
new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked)
{
Person element = (Person) viewHolder.checkBox.getTag();
data[position].setCheck(isChecked);
if(isChecked)
{
// do your stuff
}
else
{
//to-do
}
}
}
Upvotes: 2
Reputation: 921
You didn't cover the case convertView != null, this is what happens when scrolling up and down. You should implement a way to recycle the convertView (better) or just ignore it and give a fresh View back in this case too (worse).
Upvotes: 1