I have listview with custom adapter. Every element of this listview has checkbox. Standart function .isChecked() does not work.
someActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
btnShare.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
List<Boolean> listCheck;
listCheck = new ArrayList<Boolean>();
for (int i = 0; i < CA_main_trx.editModelArrayList.size(); i++){
Boolean stat = CA_main_trx.editModelArrayList.get(i).getCheckShare();
String nilaiPcs = CA_main_trx.editModelArrayList.get(i).getTextView_main_trx2();
Log.d(TAG, "onClick: --a" + nilaiPcs);
Log.d(TAG, "onClick: --a" + stat);
}
}
});
CustomeAdapter
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
final String TAG = "CA_Main_Trx : ";
...
holder.checkShare.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if(b){
String id = editModelArrayList.get(position).getTextView_main_trx0();
Log.d(TAG, "onCheckedChanged: True"+id);
}
else
Log.d(TAG, "onCheckedChanged: False");
}
});
...
model
package com.m.t;
public class EM_main_trx {
private boolean checkShare;
public Boolean getCheckShare() {return checkShare;}
public void setCheckShare(Boolean checkShare) {
this.checkShare = checkShare;
}
}
When checked in custome Adapter i get the checked status. But when i get the data using button in my mainactivity i got stuck. just got null.
Some my reference :
Android: Get checked checkbox values
Finding the Checked state of checkbox in a custom listview
how to get the the multiple checkbox values using custom adapter in android
Android List View Custom Adapter with Checkbox multiple selection and Search Listview
Checked values of CheckBox with Custom Listview android
Just update part of custome adapter to this :
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
editModelArrayList.get(position).setCheckShare(b);
}
Related
I'm adding radiogroups programatically to my recyclerview and it's working fine.
But when I check it and scroll the recyclerview it loses checked radios.
I've seen many ways and examples of solutions, but I cannot achieve it. It's been some days in a row.
I'm saving the checked radio in model as you can see in code below.
Adapter:
#Override
public void onBindViewHolder(final NROptionLineHolder holder, int position) {
holder.priceGroup.removeAllViews();
holder.priceGroup.setOnCheckedChangeListener(null);
int id = (position+1)*100;
checklistModel = mChecklists.get(position);
holder.packageName.setText(checklistModel.getTitle());
for(String price : checklistModel.getQuestions()){
RadioButton rb = new RadioButton(NROptionLineAdapter.this.context);
rb.setId(id++);
rb.setText(price);
holder.priceGroup.addView(rb);
}
holder.priceGroup.check(checklistModel.getSelectedId());
holder.priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
checklistModel.setSelectedId(checkedId);
Log.d(TAG, "onCheckedChanged: " + checkedId);
}
});
}
Holder
OnNROptionListener onNROptionListener;
public NROptionLineHolder(View itemView, OnNROptionListener onNROptionListener) {
super(itemView);
packageName = itemView.findViewById(R.id.package_name);
priceGroup = itemView.findViewById(R.id.price_grp);
// priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
// #Override
// public void onCheckedChanged(RadioGroup radioGroup, int i) {
//
// Log.d(TAG, "onCheckedChanged: " + radioGroup.getCheckedRadioButtonId() + " " + i);
// }
// });
this.onNROptionListener = onNROptionListener;
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
onNROptionListener.onNROptionClick(getAdapterPosition());
}
public interface OnNROptionListener {
void onNROptionClick(int position);
}
}
EDIT 1 - Radio Group
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/package_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RadioGroup
android:id="#+id/price_grp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#+id/package_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:orientation="horizontal"/>
</android.support.constraint.ConstraintLayout>
EDIT 2
As requested, here is the important code from my ChecklistActivity
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checklist);
intent = getIntent();
size = intent.getIntExtra("size", 0);
nr = intent.getIntExtra("nr", 0);
Log.d(TAG, "Checklist Activity - Qtd Questões: " + size);
Log.d(TAG, "Checklist Activity - NR: " + nr);
btnSaveCheck = findViewById(R.id.btnSaveChecklist);
mRecyclerView = findViewById(R.id.package_lst);
setupRecycler();
btnSaveCheck.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Sucesso", Toast.LENGTH_SHORT).show();
}
});
}
private void setupRecycler() {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
setupList();
mAdapter = new NROptionLineAdapter(data, this, getApplication());
mRecyclerView.setAdapter(mAdapter);
}
private void setupList(){
data = new ArrayList<>();
class setupList extends AsyncTask<Void, Void, List<MRNrOption>> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected List<MRNrOption> doInBackground(Void... voids) {
list = DatabaseClient
.getInstance(getApplicationContext())
.getAppDatabase()
.mrNrOptionDAO()
.loadAllByNRId(nr);
return list;
}
#Override
protected void onPostExecute(List<MRNrOption> list) {
super.onPostExecute(list);
List<String> priceList = new ArrayList<>();
priceList.add("Sim");
priceList.add("Não");
priceList.add("Não se Aplica");
for (int i=0; i<list.size(); i++) {
Log.d(TAG, "NRs Activity - Adding To List: " + list.get(i).getTitle());
data.add(new Checklist(
list.get(i).getTitle(),
priceList)
);
mAdapter.notifyDataSetChanged();
}
}
}
setupList lm = new setupList();
lm.execute();
}
EDIT 3 - Important
The RadioGroups and RadioButtons are programatically generated because I'm getting all questions from server, the number of questions are different depending on previous selections made by user, that's why I need it this way.
EDIT 4
GIF to enhance the problem visualization
EDIT 5 - Checklist Model Class
public class Checklist {
String title;
List<String> questions;
boolean isRadioButtonAdded;
int selectedId;
public Checklist(String title, List<String> questions) {
this.title = title;
this.questions = questions;
}
public Checklist(){}
public boolean getIsAdded(){
return isRadioButtonAdded;
}
public void setIsAdded(boolean isAdded){
this.isRadioButtonAdded = isAdded;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getQuestions() {
return questions;
}
public void setQuestions(List<String> questions) {
this.questions = questions;
}
public int getSelectedId() {
return selectedId;
}
public void setSelectedId(int selectedId) {
this.selectedId = selectedId;
}
}
Though i'm not sure as to whether this will solve your problem or not, but as an optimiziation also a good practice you should attach listeners to the onCreateViewHolder instead of the onBindViewHolder this prevents multiple objects from getting created for the listener.
Why dont you move this code inside the onCreateViewHolder
this block inside the view holder you have:
priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
checklistModel.setSelectedId(checkedId);
Log.d(TAG, "onCheckedChanged: " + checkedId);
}
});
Try moving your setOnCheckedChangeListener code to ViewHolder and update your mCheckList here:
priceGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
mCheckList.get(getAdapterPosition()).setSelectedId(checkedId);
Log.d(TAG, "onCheckedChanged: " + radioGroup.getCheckedRadioButtonId() + " " + i);
}});
Main problem is that you're not updating correct items state. When you click on radio button it will update only last item onBindViewHolder called because checklistModel holds only last reference. To fix this you always need to access mainList inside listeners.
Save the checked / unchecked status of the radio button to your model (i.e. your items in the list should have a field for this) when the onClick event happens. When you bind the ViewHolder, make sure you set checkbox's value to whatever you saved in your model.
The unique working solution was to set RecyclerView to not recycleable in ViewHolder.
this.setIsRecyclable(false);
How about the following code?
Adapter:
Since the view is recycled, I thought that the unique id is a mistake.
int id = (position+1)*100;
to
int id = 1;
The way recyclerview works is that when you scroll down or up until the view is invisible, it will store the state but when you scroll down recyclerview or scroll up recyclerview it will destroy the row and it will put a new row into that position.so the entire row's view will be destroyed.
The solution to the question is that you add another variable to the list you are using and when the radio button changes state you store the data and move on.
like this in your data model class
And in Model Class you define which list is recyclerview is using.
Boolean is stateclicked;
int state position;
and in OnBindViewholder you can get the value of this data. If the value is null then it's not clicked and if it is clicked then you change the boolean to yes and put the state's value into the integer
I am creating a sample application containing an Activity [having ListView and Button] in layout file. ListView is custom containing [Label/Name and CheckBox]. I want to write some code which will change text of the Button from adapter class of ListView based on List Item CheckBox check [T/F].
listView.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
// When clicked, show a toast with the TextView text
AppListOfAllApps Selecteditems = (AppListOfAllApps) parent.getItemAtPosition(position);
if (view != null)
{
CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkBox1);
Selecteditems = (AppListOfAllApps) checkBox.getTag();
//here you will get the selected item you may also get the text from it accordingly and then using using button variable just set text
button.settext("whatever");
}
}
});
In Activity :
public class Your_Activity extends Activity implements OnCheckListener// Implement your listener here
#Override
public void OnCheck(int position) {
// TODO Auto-generated method stub
// notify your activity component here
}
In Adapter class :
private OnCheckListener listener;
public interface OnCheckListener {
public void OnCheck(int position);
}
public Your_adapter_constructor(OnCheckListener listener) {
// TODO Auto-generated constructor stub
this.listener = listener;
}
// On your getView()
checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
listener.OnCheck(position);// If you want to pass some value add it here
}
});
I want to delete selected rows from a todo list by clicking on the checkbox and deleting them trough the delete button, for that I am within my custom adapter setting a setOnCheckedChangeListener on my checkbox and setOnClickListener on my delete button, now keep in mind that the delete button is inflated on my fragment view and I am using it on my row view, but the problem is only the last element from my todo list is getting deleted not the rest of them, I tried working within the fragment view and notify the adapter later on but all I got was a null pointer error on my checkbox.
Row View:
todoCheckBox = (CheckBox) convertView.findViewById(R.id.todo_CheckBox);
todoTextView.setText(values.get(position));
todoCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//Toast.makeText(getContext(), " CheckBox Status: " + isChecked, Toast.LENGTH_LONG).show();
mDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mDelete.isPressed() && (todoCheckBox.isChecked())) {
//convertView.clearFocus(position);
mAdapter.clear();
//mAdapter.notifyDataSetChanged();
}
}
});
}
});
Fragment View:
#TargetApi(9) // remember this for isEmpty()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_todo, container, false);
ArrayList<String> todoList = new ArrayList<String>();
mAdapter = new UsersAdapter(getActivity(), todoList);
listViewToDo = (ListView) v.findViewById (android.R.id.list);
listViewToDo.setAdapter(mAdapter);
mToDoField = (EditText) v.findViewById(R.id.todo_editText);
mDelete = (Button) v.findViewById(R.id.delete_button);
mAdd = (Button)v.findViewById(R.id.add_button);
mAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String toDo = mToDoField.getText().toString().trim();
if (toDo.isEmpty()){
return;
}
mAdapter.add(toDo);
mToDoField.setText("");
}
});
return v;
}
}
You need to assign an onclick listener to your delete button outside of the onChecked statement. Add it in code just after you assign the onClick event to the add button. This is because a view in android can only have 1 listener per event type.
The onClick event can look something like below using a sparese
mDelete.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
SparseBooleanArray checked = listViewToDo.getCheckedItemPositions();
for (int i = 0; i < listViewToDo.getCount(); i++){
if (checked.get(i)==true)
{
mAdapter.remove(i);
}
mAdapter.notifyDataSetChanged();
}
listViewToDo.clearChoices();
}
});
I am having trouble figuring this one out.
I have a ListView with CursorAdapter and if item goes offscreen the switch resets it self. I have a listener onCheckedChangeListener set on the switch, which triggers the listener implemented by hosting fragment that updates a field in database table and requeries the whole thing (contentResolver.notifyChange()).
I know this is kinda usual issue with check boxes, but I still cant get it working.
public class FilterCursorAdapter extends CursorAdapter {
public interface OnSwitchToggledListener {
public void onSwitchToggled(int id, boolean isActivated);
}
private OnSwitchToggledListener listener;
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = layoutInflater.inflate(R.layout.filter_item, parent, false);
ViewHolder holder = new ViewHolder();
holder.keywordTextView = (TextView) view.findViewById(R.id.keyword_text_view);
holder.cathegoryTextView = (TextView) view.findViewById(R.id.cathegory_text_view);
holder.activateSwitch = (Switch) view.findViewById(R.id.switch_activate);
view.setTag(holder);
return view;
}
public void bindView(View row, final Context context, final Cursor cursor) {
final ViewHolder holder = (ViewHolder) row.getTag();
holder.keywordTextView.setText(cursor.getString(cursor.getColumnIndex(ArticleProvider.COLUMN_KEYOWRD)));
final int id = cursor.getInt(cursor.getColumnIndex(ArticleProvider.COLUMN_FILTER_ID));
String cathegory = cursor.getString(cursor.getColumnIndex(ArticleProvider.COLUMN_CATHEGORY));
int isActivated = cursor.getInt(cursor.getColumnIndex(ArticleProvider.COLUMN_ACTIVATED));
holder.cathegoryTextView.setText(string);
holder.activateSwitch.setChecked(isActivated == 1);
holder.activateSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
listener.onSwitchToggled(id, isChecked);
}
});
}
private class ViewHolder {
public TextView keywordTextView;
public TextView cathegoryTextView;
public Switch activateSwitch;
}
}
public class FilterListFragment extends SherlockListFragment implements LoaderCallbacks<Cursor>, OnSwitchToggledListener {
#Override
public void onSwitchToggled(int id, boolean isActivated) {
Log.d(MainActivity.TAG, "ID: " + id + " isActivated: " + isActivated);
ContentValues values = new ContentValues();
values.put(ArticleProvider.COLUMN_ACTIVATED, isActivated);
resolver.update(ArticleProvider.FILTERS_URI, values, ArticleProvider.COLUMN_FILTER_ID + "=" + id, null);
}
}
From the logs it seems that the setOnCheckedChangeListener listener inside bindView gets triggered on it self.
How do I fix this one? Also I would like to note that I am using SwitchCompatLibrary (https://github.com/ankri/SwitchCompatLibrary)
Thanks!
If you face this problem, you need to add remove the listener before setting it again
holder.activateSwitch.setOnCheckedChangeListener(null)
I was having the same problem with this for about three hours today. As soon as it moved off screen, it changed. So, I ended up abandoning theonCheckedChanged listener and instead used:
mySwitch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i(TAG, "isChecked:");
}
});
Now it works perfect.
I have a ListView with CheckBox on it. and i am using Custom Adapter to populate the ListView.
In my xml file i have a Button at bottom. what i want is let user select number of rows in ListView and when he/she clicked on the Button get the position of the selected items so that i could get the object for particular row for further calculations.
In the customadapter's getview method, do
//use the actual id of your checkbox of course
Checkbox checkbox = (CheckBox)findViewById(R.id.checkbox);
checkbox.setFocusable(false);
checkbox.setFocusableInTouchMode(false);
now the checkbox is clickable as is the listitem.
To solve this problem you will have to create a custom Item class which will represent your individual checkboxes on the list. The array of these items will then be used by the adapter class to display your check boxes.
This Item class will have a boolean variable isSelected which will determine if the checkbox is selected or not. You will have to set the value of this variable in your OnClick Method of your custom adapter class
For Example
class CheckBoxItem{
boolean isSelected;
public void setSelected(boolean val) {
this.isSelected = val;
}
boolean isSelected(){
return isSelected;
}
}
For your CustomAdapter Class which look like following:
public class ItemsAdapter extends ArrayAdapter implements OnClickListener {
// you will have to initialize below in the constructor
CheckBoxItem items[];
// You will have to create your check boxes here and set the position of your check box
/// with help of setTag method of View as defined in below method, you will use this later // in your onClick method
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
CheckBox cBox = null;
if (v == null) {
LayoutInflater vi = (LayoutInflater) apUI.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.attachphoto, null);
}
CheckBoxItemItem it = items[position];
cBox =(CheckBox) v.findViewById(R.id.apCheckBox);
cBox.setOnClickListener(this);
cBox.setTag(""+position);
Log.d(TAG, " CHECK BOX IS: "+cBox+ " Check Box selected Value: "+cBox.isChecked()+" Selection: "+it.isSelected());
if(cBox != null){
cBox.setText("");
cBox.setChecked(it.isSelected());
}
return v;
}
public void onClick(View v) {
CheckBox cBox =(CheckBox) v.findViewById(R.id.apCheckBox);
int position = Integer.parseInt((String) v.getTag());
Log.d(TAG, "CLicked ..."+cBox.isChecked());
items[position].setSelected(cBox.isChecked());
}
}
Later you will will declare and array of your CheckBoxItem class which will be contained by your Adapter class in this case it will be ItemsAdapter class.
Then when the user presses the button you can iterate through all the items in the array and check which one is selected by using the isSelected() method of CheckBoxItem class.
In your activity you will have:
ArrayList getSelectedItems(){
ArrayList selectedItems = new ArrayList();
int size = items.length;
for(int i = 0; i<size; i++){
CheckBoxItem cItem = items[i];
if(cItem.isSelected()){
selectedItems.add(cItem);
}
}
return selectedItems;
}
I had the exact same problem. I solved it in this way
public class myActivity extends Activity {
//ActionBarSherlock mSherlock = ActionBarSherlock.wrap(this);
public ListView listview;
private ArrayList<Object> itemlist=new ArrayList<Object>();
Button button;
private myAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview=(ListView)findViewById(R.id.listview1);
button=(Button)findViewById(R.id.button1);
/*add some data to ur list*/ itemlist.add(something);
adapter=new Adapter(myActivity.this, 0, itemlist);
listview.setAdapter(adapter);
**listview.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listview.setItemsCanFocus(false);**
button.setOnClickListner(new OnClickListner()
{
#Override
public void OnClick(View v)
{
/* this returns the checked item positions in the listview*/
**ArrayList<Integer> itempositions=adapter.getcheckeditemcount();**
for(int i:itempositions)
{
/* This is the main part...u can retrieve the object in the listview which is checked and do further calculations with it*/
**Object info=adapter.getItem(i);**
Log.d(TAG,"checked object info= ",info.something);
}
}
});
}
private class myAdapter extends ArrayAdapter<Object> {
private Context context;
private ArrayList<Object> list;
**private ArrayList<Integer> checkedpositions;**
public myAdapter(Context localContext,int textViewResourceId, ArrayList<Object> objects) {
super(localContext,textViewResourceId,objects);
context = localContext;
this.list=objects;
this.checkedpositions=new ArrayList<Integer>();
//Log.d("adapter","list size= "+objects.size());
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView picturesView;
View v = convertView;
TextView Mainitem;
final CheckBox check;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.albumview, null);
Object item=list.get(position);
if(item!=null)
{
check = (CheckBox)v.findViewById(R.id.checkBox1);
/* set a tag for chekbox with the current view position */
**check.setTag(position);**
/*set a onchecked change listner for listning to state of checkbox toggle */
check.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
/*get the tag of the checkbox...in this case this will give the (position of view)*/
Object tag=check.getTag();
if ( isChecked )
{
// perform logic
count++;
Log.d("Checkbox","added "+tag);
checkedpositions.add((Integer) tag);
}
else
{
count--;
checkedpositions.remove(tag);
Log.d("Checkbox","removed "+(Integer)tag);
}
/* if u dont have a textview in ur listview then ignore this part */
Mainitem = (TextView) v.findViewById(R.id.textView1);
Mainitem.setText(item.Album_name);
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d("error", "wall");
}
}
}
return v;
}
/* Finally create a method which return the checkeditem postions in the listview */
**public ArrayList<Integer> getcheckeditemcount()
{
return this.checkedpositions;
}**
}
}
I hope this helps.