Search code examples
androidlistviewcheckboxcustom-cursor

Position of row in ListView that checkBox is selected


I have a listView where each row consists of a checkBox, TextView and Button. The button is set to GONE. When the user selects the textBox I want the button to become visible. The user will then click this button to remove the row.

I have implemented a listener for the checkBox, which works, but what I cannot work out is how to make sure the appropriate deleteButton is made visible. With my current code a random button is made visible.

What should I do? A point towards a tutorial or a code fragment would be very helpful.

public class DeleteCampaignCustomCursorAdapater extends CursorAdapter {

protected static final String TAG = null;
DatabaseHelper myDbHelper;
protected SQLiteDatabase db;

private final LayoutInflater mInflater;
protected ListView mListView;

TextView merchantNameView;
Button deleteButton;
CheckBox selectForDelete;
//ImageView moveButton;

public DeleteCampaignCustomCursorAdapater(Context context, Cursor c) {
    super(context, c);
    mInflater = LayoutInflater.from(context);
}

@Override
public void bindView(View view, Context context, final Cursor cursor) {

    myDbHelper = new DatabaseHelper(context); //Links to DatabaseHelper class

    merchantNameView = (TextView) view.findViewById(R.id.deleteMerchantNameView);
    deleteButton = (Button) view.findViewById(R.id.deleteButton);
    selectForDelete = (CheckBox) view.findViewById(R.id.deleteCheckBox);
    //moveButton = (ImageView) view.findViewById(R.id.moveButton);

    merchantNameView.setText(cursor.getString(cursor.getColumnIndex("merchantName")));

    final int  rowID = cursor.getInt(cursor.getColumnIndex("_id"));
    //final long rowID = mListView.getSelectedItemId();

    selectForDelete.setOnCheckedChangeListener(new OnCheckedChangeListener()
    {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
        {
            if ( isChecked )
            {
                // perform logic
                deleteButton.setVisibility(0);
            }
            else {
                deleteButton.setVisibility(8);
            }
        }
    });

    //deleteButton.setOnClickListener(new DeleteEntryOnClicklistener(itemID));  
    deleteButton.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {

            if(rowID > 0) {
                //Log.d(TAG, "Button Click. rowID = "+rowID);                   

                myDbHelper.deleteRecordWithID(rowID);
                cursor.requery();
                notifyDataSetChanged();
            }                           
        }
    });     
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    return mInflater.inflate(R.layout.delete_campaign_row_layout, null);
}

}

EDIT

My new code with Barak's advice. The first version worked but once a row was deleted the row below it would be checked once the view refreshed. Now I get a cursorOutOfBoundsException in my getView().

public class DeleteCampaignCustomCursorAdapater extends CursorAdapter {

protected static final String TAG = null;
DatabaseHelper myDbHelper;
protected SQLiteDatabase db;
private final Activity context;

private LayoutInflater mInflater;
protected ListView mListView;

private static Cursor c;
public static int[] checked;

TextView merchantNameView;
Button deleteButton;
CheckBox selectForDelete;
//ImageView moveButton;

public DeleteCampaignCustomCursorAdapater(Context context, Cursor c) {
    super(context, c);
    this.context = (Activity) context;
    mInflater = LayoutInflater.from(context);
    DeleteCampaignCustomCursorAdapater.c = c;
    initializeChecked();
}

@Override
public void bindView(View view, Context context, final Cursor cursor) {

    /*myDbHelper = new DatabaseHelper(context); //Links to DatabaseHelper class

    merchantNameView = (TextView) view.findViewById(R.id.deleteMerchantNameView);
    deleteButton = (Button) view.findViewById(R.id.deleteButton);
    //selectForDelete = (CheckBox) view.findViewById(R.id.deleteCheckBox);
    //moveButton = (ImageView) view.findViewById(R.id.moveButton);

    merchantNameView.setText(cursor.getString(cursor.getColumnIndex("merchantName")));

    final int  rowID = cursor.getInt(cursor.getColumnIndex("_id"));     
    //final long rowID = mListView.getSelectedItemId();

    if (checked[rowID] == 0) {
        selectForDelete.setChecked(false);
    } else {
        selectForDelete.setChecked(true);
    }


    selectForDelete.setOnCheckedChangeListener(new OnCheckedChangeListener()
    {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
        {
            if ( isChecked )
            {
               // Make deleteButton appear 
               RelativeLayout ll = (RelativeLayout) buttonView.getParent();
               deleteButton = (Button) ll.findViewById(R.id.deleteButton);
               checked[rowID] = 1;
               deleteButton.setVisibility(0);
            }
            else {
                //Hide deleteButton
                RelativeLayout ll = (RelativeLayout) buttonView.getParent();
                deleteButton = (Button) ll.findViewById(R.id.deleteButton);
                checked[rowID] = 1;
                deleteButton.setVisibility(8);
            }
        }
    });

    deleteButton.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {

            if(rowID > 0) {
                //Log.d(TAG, "Button Click. rowID = "+rowID);                   

                myDbHelper.deleteRecordWithID(rowID);
                cursor.requery();
                notifyDataSetChanged();
                initializeChecked();  // re-set the checked array
            }                           
        }
    }); */
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    return mInflater.inflate(R.layout.delete_campaign_row_layout, null);
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {

    myDbHelper = new DatabaseHelper(context); //Links to DatabaseHelper class

    if (convertView == null) {
        mInflater = context.getLayoutInflater();
        convertView = mInflater.inflate(R.layout.delete_campaign_row_layout, null);
    }       

    merchantNameView = (TextView) convertView.findViewById(R.id.deleteMerchantNameView);
    deleteButton = (Button) convertView.findViewById(R.id.deleteButton);
    selectForDelete = (CheckBox) convertView.findViewById(R.id.deleteCheckBox);     

    merchantNameView.setText(c.getString(c.getColumnIndex("merchantName")));

    final int  rowID = c.getInt(c.getColumnIndex("_id"));       
    //final long rowID = mListView.getSelectedItemId();

    if (checked[position] == 0) {
        selectForDelete.setChecked(false);
    } else {
        selectForDelete.setChecked(true);
    }

    selectForDelete.setOnCheckedChangeListener(new OnCheckedChangeListener()
    {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
        {
            if ( isChecked )
            {
               // Make deleteButton appear 
               RelativeLayout ll = (RelativeLayout) buttonView.getParent();
               deleteButton = (Button) ll.findViewById(R.id.deleteButton);
               checked[position] = 1;
               deleteButton.setVisibility(0);
            }
            else {
                //Hide deleteButton
                RelativeLayout ll = (RelativeLayout) buttonView.getParent();
                deleteButton = (Button) ll.findViewById(R.id.deleteButton);
                checked[position] = 1;
                deleteButton.setVisibility(8);
            }
        }
    });

    deleteButton.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {

            if(rowID > 0) {
                //Log.d(TAG, "Button Click. rowID = "+rowID);                   

                myDbHelper.deleteRecordWithID(rowID);
                c.requery();
                notifyDataSetChanged();
                initializeChecked();  // re-set the checked array
            }                           
        }
    });

    return convertView;     
}

public static void initializeChecked() {
    checked = new int[c.getCount()];
    int i = 0;
    while (i < c.getCount()) {
        checked[i] = 0;
        i++;
    }
}

}


Solution

  • You could do this:

    selectForDelete.setOnCheckedChangeListener(new OnCheckedChangeListener()
    {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
        {
            if ( isChecked )
            {
               // perform logic 
               LinearLayout ll = (LinearLayout) buttonView.getparent();
               Button b = (Button) ll.findViewById(R.id.deleteButton)
               b.setVisibility(0);
            }
            else {
               LinearLayout ll = (LinearLayout) buttonView.getparent();
               Button b = (Button) ll.findViewById(R.id.deleteButton)
               b.setVisibility(8);
            }
        }
    });
    

    You've checked the box, so you know the row, get the parent of the checkbox (which should be the LinearLayout of the row), then get the button id for that row and use that to set the delete button visibility for that specific row/view.

    Hope this helps.

    EDIT

    To fix your issues on delete you need to do something like follows.

    In the custom adapter set an array:

    private Cursor c;
    public static int[] checked;
    

    In your constructor set your cursor to the local var and call a method:

    CursorAdapter_EditText.c = c;
    initializeChecked();
    

    The method:

    public static void initializeChecked() {
        checked = new int[c.getCount()];
        int i = 0;
        while (i < c.getCount()) {
            checked[i] = 0;
            i++;
        }
    }
    

    In your bindview, re-arrange and add a couple lines:

    final int  rowID = cursor.getInt(cursor.getColumnIndex("_id"));
    selectForDelete = (CheckBox) view.findViewById(R.id.deleteCheckBox);
    if (checked(rowID) == 0) {
        selectForDelete.setChecked(false);
    } else {
        selectForDelete.setChecked(true);
    }
    

    Then in modify my original answer onCheckedChanged like so::

    selectForDelete.setOnCheckedChangeListener(new OnCheckedChangeListener()
    {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
        {
            if ( isChecked )
            {
               // perform logic 
               LinearLayout ll = (LinearLayout) buttonView.getparent();
               Button b = (Button) ll.findViewById(R.id.deleteButton);
               checked[posSelected] = 1;
               b.setVisibility(0);
            }
            else {
               LinearLayout ll = (LinearLayout) buttonView.getparent();
               Button b = (Button) ll.findViewById(R.id.deleteButton);
               checked[posSelected] = 1;
               b.setVisibility(8);
            }
        }
    });
    

    Finally in your delete button listener:

    deleteButton.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {
    
            if(rowID > 0) {
                //Log.d(TAG, "Button Click. rowID = "+rowID);                   
    
                myDbHelper.deleteRecordWithID(rowID);
                cursor.requery();
                notifyDataSetChanged();
                initializeChecked();  // re-set the checked array
            }                           
        }
    });