I currently have a ListView in my Android app that has a CheckBox on the side.
When the checkbox is changed I want to get some info from the listview row that the button is in and then persist it, however, I can not work out how to get the row data from the onClickChanged listener.
My listview is populated using a custom JSONObject listadapter, I am hoping it is something similar to working out what row is selected when detecting the onLongTouch - for example below is the code I use to get the relevant JSON object for the row selected on a longTouch:
public boolean onContextItemSelected(MenuItem item) {
//get row selected information
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
JSONObject selected = (JSONObject) getListAdapter().getItem(menuInfo.position);
The above is obviously within my ListActivity, and my onCheckChanged listener would not be in the same activity (as it is defined in the row rather than the list)
Any help would be appreciated!
One possible way to solve this is to attach some info to the checkbox when binding occurs.
In your Adapter, add (or modify) the bindView override like this to add a tag thatcontains the context information you need:
#Override
public void bindView( View view, Context context, Cursor cursor){
CheckBox checker = (CheckBox)view.findViewById(R.id.checkbox);
checker.setOnCheckedChangeListener(MyActivity.this);
checker.setTag(Long.valueOf(cursor.getLong(cursor.getColumnIndex(BaseColumns._ID))));
// call super class for default binding
super.bindView(view,context,cursor);
}
(or attach any other value to the checkbox that helps you identify the item, e.g. the propery name or index)
Then, in the onCheckedChanged, you can refer to this information to identify the item that was changed:
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Long id = (Long) buttonView.getTag();
if ( id!=null)
Log.d(TAG, "onCheckedChanged id="+id);
}
Related
Hello I'm having an issue getting all of the items from my adapter in my fragment. To be more specific I am using a ScaleInAnimatorAdapter along with my Customer Adapter and when I attempt to get my checkbox items from the below posted code, within my Fragment, I only seem to get the visible items on screen.
private View.OnClickListener onAllClick = new View.OnClickListener() {
#Override public void onClick(View v) {
int count = listAdapter.getItemCount();
for (int i = 0; i < count; i++) {
View mChild = listTopics.getChildAt(i);
if( mChild != null ) {
Log.d(TAG,"getItemCount(): " + i );
CheckBox cBox = (CheckBox)mChild.findViewById(R.id.topic_chk);
cBox.setChecked(((CheckBox) v).isChecked());
Log.d(TAG,"isChecked" + cBox.getTag());
cBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(((CheckBox) v).isChecked()) {
checkboxAll.setChecked(false);
}
}
});
}
}
}
};
Essentially I am attempting to create a check all feature from the fragment, so that when this is clicked all of the checkbox items from the adapter are checked. I got that to work with the code I presented however the main issue is that I only get the items visible on the screen, so when I scroll to my other items they are not checked. Thus I am wondering if there is a better way or another way for me to get all of the items
Adapters are meant to bind underlying data stores to views; they generally shouldn't be used to store data themselves (except for having a copy of the data for view binding purposes) nor should they perform actions on data.
Instead, you should be modifying the underlying data, then updating the adapter through whatever mechanism you are already using. (Loaders, custom setters with notifyDataItemChanged, etc.).
Basically you can't. It'll be reusing the UI views.
You need to set a flag in all your data list objects, call notifyDataSetChanged() and onBindViewHolder check that flag and use it to check uncheck
if(listAdapter.getItem(position).getIsChecked())
viewHolder.checkBox.setChecked(true);
else
viewHolder.checkBox.setChecked(false);
Ok. Thank you all for those who have replied you helped me grasp something really basic and important that had alluded me.
I got it to work, so for anyone who might read this post, here is my solution:
Create necessary methods and field to update your data in a model (ie, private is_checked, set_checked(), is_checked(), etc)
In your adapter onBindViewHolder, you will set your holder checkbox to be associated to the data so something like:
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
obj.setSelected(buttonView.isChecked());
}
});
holder.checkBox.setChecked(obj.isSelected());
Then in your fragment or activity I just have a click listener on my main checkbox, and then when checked I loop through my data list, and using the model method I update my data and just simply use listAdapter.notifyDataSetChanged()
You are doing it wrongly.
You should update the adapter instead of updating the check box view.
What you can do , you can create a field in adapter data holder .
And whenever you change the selection,just update the field or multiple field and finally refresh the view.
I have a custom list view and each item of it has a check box and a text field. I want to disable the check box in every other row of the list view if the check box of the first row is enabled.
Since you are stating that if the first check box is clicked all the others should be disabled, do a check in your onBindView() to see if the checkbox is checked. if it is, set a value to say that it is, and for all the following list view entries set the checkbox to disabled.
In your onCheckChangedListener():
checkbox1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked()){
firstCheckboxChecked = true;
}
});
Then in your onBindView for the rest:
if(firstCheckBoxChecked){
checkbox.setEnabled(false);
}
Here I am putting some rough solution which will help you.
classs model
{
boolean status;
model(boolean status){
this.status=status;
}
}
List<model> list_model= new ArrayList<>();
list_model.add(false);
list_model.add(false);
list_model.add(false);
list_model.add(false);
add this model with listview adapter.
//Adapter coding
checkbox.checked(check)
//write below code in checkbox.setOncheckedItemSelect method.
//you will get already checked parameter in that method.which will put into list
list_model.add(checked);
//here call listview notify datasetchangedListener.
create a boolean variable isFirstEnbled in your adapter. then on click first item's checkbox set this value as isFirstEnbled=true .
adapter.notifyDataSetChanged()
This recreate the view with isFirstEnabled set as true
Could someone please explain the different ways of making checkbox list and saving the checked option? It would be nice if you could attach examples. I am using arraylist to save input, what are the other ways?
final CharSequence[] items = {};
final ArrayList seletedItems = new ArrayList();
Define your ListItem object to have a 'checked' field
class ListItem{
boolean isChecked=false;
}
In your list adapter's getView attach a onCheckedChangeListener to the CheckBox and change the checked state of your object. something like:
final MessageItem Message=getItem(position);
message.setText(Message.text);
//set data
select.setOnCheckedChangeListener(null); //important so that when reusing the view the old listener isn't called
select.setChecked(Message.selected);
select.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
Message.selected=isChecked;
}
});
You can create a custom class for objects like,
public class entity
{
public boolean isChecked;
//Any other variables can also be created
}
On check box selection change the value of
entityobj[index].isChecked=true/false;
Apply a custom list adapter,
in adapters getview() method you can check for isChecked value and then either check or uncheck the respective checkbox,
using this your selection will persist while scrolling also..
Hope it will help...
I have a listview that contains a checkedtextview. My app moves from the top of the list view to the bottom. I want to check if the item is checked before calling an action. If it is not checked I want to move to the next item in the list.
E.g.
Item 1 - Checked
item 2 - Checked
Item 3 - Not Checked
Item 4 - Checked
So, I want the app to process as follows:
Item 1
Item 2
Item 4.
I am not sure how to access the checked status of the item from the listview position.
The logic that I want is as follows:
Is Current Item checked?
Yes:
Call action
No:
Move to next item.
Reloop to top of void.
I will need something in there to stop an infinite loop.
1.) First create an array, what indicates the items checked state in your adapter
(assuming you extend the BaseAdapter class for this purpose):
private boolean [] itemsChecked = new boolean [getCount()];
2.) Then create an OnCheckedChangeListener:
private OnCheckedChangeListener listener = new OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton button, boolean checked)
{
Integer index = (Integer)button.getTag();
itemsChecked[index] = checked;
}
}
3.) In your adapters getView() method:
public View getView(int index, View view, ViewGroup parent)
{
/*...*/
CheckBox checkBox = /*get the checkbox*/;
checkbox.setTag(index);
checkBox.setOnCheckedChangeListener(listener);
/*...*/
}
4.) In the onClick() method:
public void onClick(View view)
{
//just get the boolean array somehow
boolean [] itemsChecked = adapter.getItemsCheckedArray();
for(int i=0; i<itemsChecked.length; i++)
{
if(itemsChecked[i])
{
//the i th item was checked
}
else
{
//it isnt checked
}
}
}
One solution will be to use an ArrayList of positions.
When the user check/uncheck a checkbox, add/remove accordingly the position in your ArrayList.
Then when the user is over, just iterate through the list to know which position have been selected.
I have an activity that has a checkbox, then under it is a list of contacts populating my listview with checkboxes for each contact. I have two major problems stemming from my question.
chkbox_foo is outside of the listview, and chk_bar is inside. chk_foo works, but anything related to chk_bar after being initialized causes the app to crash. Also, if I create a setOnCheckedChangeListener for chkbox_bar, that will cause the app to crash also. Does anyone know why this is happening and how I can fix this?
btn_foo = (Button) findViewById(R.id.btn_foo);
barList = (ListView) findViewById(R.id.lv_barList);
chk_foo = (CheckBox) findViewById(R.id.cb_foo);
chk_bar = (CheckBox) findViewById(R.id.cb_bar);
// set checkboxes state as false at beginning
chkboxAllVisible = false;
chkboxSingleChk = false;
chk_foo.setChecked(chkboxAllVisible);
chk_bar.setChecked(chkboxChk); <---App crashes here
// Outside of listview checkbox
chk_foo.setOnCheckedChangeListener(new OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
Log.d(TAG, "checkbox changed " + isChecked);
if(isChecked){
chkboxAllVisible = true;
chk_bar.setChecked(isChecked); <---app crashes here too
}
}
});
// Outside of listview checkbox
chk_bar.setOnCheckedChangeListen... <---app crashes here also
When the user clicks on your "master" checkbox you will need to iterate through the list that is bound to your ListView. Then by accessing each row individually can you mark each row's checkbox.
Please post the code for your ListView if you want a specific example.
chk_bar is probably null. You can't call findViewByID on the main layout if the checkbox is inside a listview. You have to call it on the layout where it is housed/contained, which would be the listview item.
That said, you don't need to do that. If you have contacts with checkboxes, I'm guessing you are using some sort of custom adapter? If so, good, then it this will be easy. I'm also assuming you are keeping track of whether or not an item/contact has been checked (if not, you'll need to implement that anyways, see tutorial below)
In your getView of your custom adapter, while generating the view, you need to look at the data object and if the IsChecked value is true, then you check the checkbox.
public View getView(int position, View convertView, ViewGroup parent)
{
//Inflate your view
//View listViewLayout = ...
//Here is where you get the reference to the checkbox
Checkbox chkBox = (CheckBox)listViewLayout.findViewById(R.id.cb_bar);
//Get the data object from whatever your source is (maybe an array list?)
SomeObj curObj = (SomeObj)listOfItems.get(position);
chkBox.setChecked(curObj.IsChecked);
}
Here is a full tutorial on how to implement a custom Adapter for Listview:
http://www.ezzylearning.com/tutorial.aspx?tid=1763429&q=customizing-android-listview-items-with-custom-arrayadapter
Once you have that working, the rest is simple:
When the user clicks the master checkbox:
Regenerate the list of items but force all the checkbox values to true.
Call adapter.notifyDataSetChanged()
When you call notifyDataSetChanged() the listview will re-draw itself (if it believes the source items have in fact been changed. See this: notifyDataSetChanged example)
When it regenerates the listview, it will iterate through your source items you passed in, and since you regenerated the list and marked all items as "IsChecked" (or whatever your variable name is), it will check each checkbox.