0

I'm developing an application that uses a check list to inform the state from a vehicle.

I'm using a Custom Adater for the ListView with a TextView and two Checkboxes.

The checkboxes are used to indicate that the characteristic meets or not an revision.

Actually the list has seven items but in the phone are displayed only six, because of the layout size, the problem is not here. the problem is the reuse of the View in the ListView, when check the first or second position, the sixth and seventh get checked too when i scroll to them, but the text of the TextView is show properly.

I have read these questions but I don't know to do now:

Duplicated entries in ListView

TextView in listview rows showing repeated values on scroll in Android?

List items position repeating in getview

Android Listview row repeating item <--- this question show my problem

The tutorial that I made

The code:

ListAdapter:

public class ListAdapter extends ArrayAdapter<String> {

Context context;
int layoutResourceId;
String data[] = null;
LayoutInflater inflater;
boolean[] cumpleCheckboxState;
boolean[] noCumpleCheckboxState;

public ListAdapter(Context context, int layoutResourceId,
        String[] data) {
    super(context, layoutResourceId, data);
    this.layoutResourceId = layoutResourceId;
    this.context = context;
    this.data = data;
    cumpleCheckboxState = new boolean[data.length];
    noCumpleCheckboxState = new boolean[data.length];

}

    @Override
public View getView(final int position, final View convertView, ViewGroup parent) {
    View row = convertView;
    final MatrixHolder holder;

    if (row == null) {
        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        row = inflater.inflate(layoutResourceId, parent, false);
        holder = new MatrixHolder();
        holder.txtTitle = (TextView) row.findViewById(R.id.headingitem);
        holder.cumpleCheckbox = (CheckBox) row.findViewById(R.id.cumple);
        holder.noCumpleCheckbox = (CheckBox) row.findViewById(R.id.noCumple);
        holder.cumpleCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.e("Position","Nro.: " + position + " " + isChecked);
                cumpleCheckboxState[position] = isChecked;
            }
        });
        holder.noCumpleCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.e("Position","Nro.: " + position + " " + isChecked);
                noCumpleCheckboxState[position] = isChecked;
            }
        });
        row.setTag(holder);
    } else {
        holder = (MatrixHolder) row.getTag();
    }
    for (int i = 0; i < cumpleCheckboxState.length; i++) {
        Log.e("Estados","item: " + i + " Posicion:" + cumpleCheckboxState[i]);
    }
    Log.e("Position","Posicion:" + position);
    holder.txtTitle.setText(data[position]);
    holder.cumpleCheckbox.setChecked(cumpleCheckboxState[position]);
    holder.cumpleCheckbox.setChecked(noCumpleCheckboxState[position]);
    row.setTag(holder);
    return row;
}

static class MatrixHolder {
    TextView txtTitle;
    LinearLayout layout;
    int position;
}

}

Adding the adapter:

        ListAdapter listAdapter = new ListAdapter(getContext(),R.layout.horizontal_checkbox, itemList);
        final ListView listView2 = (ListView)view.findViewById(R.id.listView);
        listView2.setAdapter(listAdapter);

List Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
    android:id="@+id/headingitem"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="left"
    android:padding="5dp"
    android:textSize="20dp"/>

<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/linearmain"
    android:layout_gravity="center_horizontal|center_vertical"
    android:orientation="horizontal" >

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Cumple"
        android:paddingLeft="2sp"
        android:paddingRight="2sp"
        android:layout_weight="1"
        android:id="@+id/cumple"
        />
    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="No Cumple"
        android:paddingLeft="2sp"
        android:paddingRight="2sp"
        android:layout_weight="1"
        android:id="@+id/noCumple"
        />
</LinearLayout>

The screenchots

Screenshots

Additional question. How to add a listener for those checkboxes and prevent to check the two checkboxes on a row

All coments or suggestions are welcome

Sorry for my bad english

EDIT: I have updated the code as @jereksel says, but im seeing that the boolean values are getting set to false when I scroll down and then up, any suggestions?

Community
  • 1
  • 1
  • When the activity opens the check boxes all are empty and the user shall then use them as input fields, that you at the end save? Is that right? – J j Oct 07 '16 at 16:12
  • @Jj Yes sir, and then I use that data to do some work in a web service. Actually the list is shown in a fragment. I came for this because the client asked for this change, but I done this with a CheckedTextView without problems, but this is more complex. T_T regards. – Numan Medina Oct 07 '16 at 16:20
  • You can take a look on my answer to: https://stackoverflow.com/questions/39926388/spannable-string-only-working-for-last-item-in-listview. That should be helpful. – i_A_mok Oct 10 '16 at 04:07

3 Answers3

0

For each checkbox you should create an array that would hold it's state:

boolean[] cumpleCheckboxState;
boolean[] noCumpleCheckboxState;

You must of course initialize them in constructor

cumpleCheckboxState = new boolean[data.length];
noCumpleCheckboxState = new boolean[data.length];

You must also add these cumpleCheckbox and noCumpleCheckbox to MatrixHolder

Then you should create listeners in getView that would change state in these arrays when checkbox is checked

holder.cumpleCheckbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView,
                                 boolean isChecked) {
        cumpleCheckboxState[position] = isChecked;
    }
}

CheckChangeListener for noCumpleCheckbox will look the same, just replace cumpleCheckboxState with noCumpleCheckboxState.

We must also add code (in getView) that will set checkbox state on new/reused views according do arrays.

holder.cumpleCheckbox.setChecked(cumpleCheckboxState[position]);
holder.noCumpleCheckbox.setChecked(noCumpleCheckboxState[position]);

If you don't want two checkboxes to be checked in once you can disable one (with setEnabled(false) when second one is being checked).

Andrew
  • 434
  • 1
  • 5
  • 13
0

I can see some issues and improvements in the code. First, why are you saving the context and the layoutResourceId in your ListAdapter constructor? you usually use the constructor to store your data set.

It looks like you are never using or referencing your checkBoxes in getView, and it is not even a property in your MatrixHolder.

You should be inflating your cell view in getView as row = inflator.inflate(R.layout.horizontal_checkbox,null) then set your matrix holder checkBox as holder.checkBox1 = row.findViewById(your_id); in the end you can just set up the click listener for each of your check boxes.

Just for curiosity? Have you thought about using a recyclerview?

Hope this helps. Here's a good link regarding listview with a checkbox. http://www.mysamplecode.com/2012/07/android-listview-checkbox-example.html

luis_lics
  • 26
  • 3
0
    @Override
    public int getViewTypeCount() {
        return getCount();
    }
    @Override
    public int getItemViewType(int position) {
        return position;
    }

Try adding it to your Adapter class! it work for me