Reputation: 583
I have a listview with checkbox and textbox .When I check the checkbox and scroll it up and down then it is automatically uncheck.
How to solve this problem in listview? please give me solution.
below i put my screen shot and code.
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lvMain"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<Button
android:id="@+id/btnSelectAll"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="Select All" >
</Button>
</LinearLayout>
list_item.xml
<?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="horizontal" >
<CheckBox
android:id="@+id/cbItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="#000000">
</CheckBox>
<TextView
android:id="@+id/tvItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000">
</TextView>
</LinearLayout>
MainActivity.java
package com.example.checkallcheckbox;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
public class MainActivity extends Activity {
ListView lvMain;
String[] name = { "Jenis", "Pratik", "Jaydeep", "Hiren", "Himansu",
"yagnik", "Atul", "Prakas", "Nihal", "Darshan", "Chetan", "Sagar",
"Nikhil", "Sanket", "Rahul", "Jigar" };
Button btnSelectAll;
boolean isSelectAll = true;
ListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvMain = (ListView) findViewById(R.id.lvMain);
btnSelectAll = (Button) findViewById(R.id.btnSelectAll);
btnSelectAll.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
if(isSelectAll)
{
adapter = new ListAdapter(getApplicationContext(), name, true);
lvMain.setAdapter(adapter);
adapter.notifyDataSetChanged();
btnSelectAll.setText("ClearAll");
isSelectAll=false;
}
else
{
adapter = new ListAdapter(getApplicationContext(), name, false);
lvMain.setAdapter(adapter);
adapter.notifyDataSetChanged();
btnSelectAll.setText("CheckAll");
isSelectAll=true;
}
}
});
adapter = new ListAdapter(getApplicationContext(), name,false);
lvMain.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
ListAdapter.java
package com.example.checkallcheckbox;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
public class ListAdapter extends BaseAdapter {
Context mContext;
String[] name;
private static LayoutInflater inflater = null;
Boolean state=false;
public ListAdapter(Context c, String[] name, boolean isSelectAll) {
// TODO Auto-generated constructor stub
mContext = c;
this.name = name;
inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
state=isSelectAll;
}
@Override
public int getCount() {
return name.length;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
public class ViewHolder {
TextView tvName;
CheckBox cbName;
}
@Override
public View getView(int position, View convertView, ViewGroup arg2) {
// TODO Auto-generated method stub
ViewHolder viewHolder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item, null);
viewHolder = new ViewHolder();
viewHolder.tvName = (TextView) convertView
.findViewById(R.id.tvItem);
viewHolder.cbName = (CheckBox) convertView
.findViewById(R.id.cbItem);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tvName.setText(name[position]);
if(state){
viewHolder.cbName.setChecked(true);
}else{
viewHolder.cbName.setChecked(false);
}
return convertView;
}
}
Upvotes: 2
Views: 6418
Reputation: 841
You should use a recyclerView and control the check states in a list, you can add an isDefault boolean is well that will get updated when there is a change in a different row. I have a tutorial for this here
holder.checkBox.setOnCheckedChangeListener { _, isChecked ->
if (item.isChecked != isChecked) {
setCheckboxTextColor(isChecked, holder)
item.isChecked = isChecked
when (item.rowType) {
RowType.TopHeader -> {
val indexList = mutableListOf<Int>()
productList.filter { it.rowType != RowType.TopHeader }.forEach {
it.isChecked = isChecked
indexList.add(productList.indexOf(it))
}
indexList.forEach {
notifyItemChanged(it)
}
}
RowType.CatHeader -> {
val indexList = mutableListOf<Int>()
productList.filter { it.rowType == RowType.ProductRow && it.category == item.category }
.forEach {
it.isChecked = isChecked
indexList.add(productList.indexOf(it))
}
indexList.forEach {
notifyItemChanged(it)
}
isAllItemsSameStatus() //for header
}
RowType.ProductRow -> {
isAllItemsSameStatus(item.category) //set prep area accordingly
isAllItemsSameStatus() //set top header
}
}
}
}
}
private fun setCheckboxTextColor(isChecked: Boolean, holder: TableViewHolder) {
if (isChecked) {
holder.checkBox.setTextColor(context.getColor(R.color.black))
} else {
holder.checkBox.setTextColor(context.getColor(R.color.grey))
}
}
private fun isAllItemsSameStatus(cat: String? = null) {
val row : RowModel
var isChecked: Boolean = true
var position: Int = 0
if(cat != null){
val catRow = productList.find { it.rowType == RowType.CatHeader && it.category == cat }
catRow?.let {
val subList = productList.filter { it.category == it.category && it.rowType == RowType.ProductRow }
isChecked = subList.filter { it.isChecked }.size == subList.size
position = productList.indexOf(catRow)
}
if(catRow == null)
return
else
row = catRow
}
else{
row = productList[0]
isChecked = productList.filter { it.rowType != RowType.TopHeader && it.isChecked }.size == productList.size - 1
position = 0
}
updateHeader(row, isChecked, position)
}
private fun updateHeader(item: RowModel, isChecked: Boolean, position: Int) {
if (item.isChecked != isChecked) // no need to update if no change
{
item.isChecked = isChecked
notifyItemChanged(position)
}
}
Upvotes: 0
Reputation: 115
I was able to resolve mine and this might help you too.
I had the same issue of auto-selection and dis-selection, when scrolling through an ArrayList of checkboxes binded on a RecyclerView.
The issue was because, in my RecyclerView adapter, I set an OnCheckedChange listener on each of the checkbox items in the ArrayList while binding data to the views, which made the checkboxes to auto-select and dis-select itself when scrolled.
See my initial code below;
holder.subCategoriesCheckBox.setOnCheckedChangeListener((compoundButton, b) -> {
if (holder.subCategoriesCheckBox.isChecked()){
holder.subCategoriesCheckBox.setChecked(false);
subCategory.setSelected(false);
}
else {
holder.subCategoriesCheckBox.setChecked(true);
subCategory.setSelected(true);
}
});
The solution was to set an OnClickListener on the checkboxes instead of OncheckedChange listener as below;
holder.subCategoriesCheckBox.setOnClickListener(view -> {
if (holder.subCategoriesCheckBox.isSelected()){
holder.subCategoriesCheckBox.setSelected(false);
subCategory.setSelected(false);
}
else {
holder.subCategoriesCheckBox.setSelected(true);
subCategory.setSelected(true);
}
});
Hope this gives you an idea on how to go about yours
Upvotes: 0
Reputation: 8847
Declare a boolean array for holding the checked state of each list item.
Initialze (using for loop) this array in constructor (all assign false).
Record the changes inside the setOnCheckedChangeListener()
.
Call setChecked()
after setOnCheckedChangeListener()
.
Upvotes: 2
Reputation: 3485
The problem is because your ListView Views are being remade. When you scroll them offscreen, android doesn't hold onto them (the list might be REALLY long so that would mean a lot of views hanging around that you can't see).
So every time you scroll an item back on-screen, Android calls getView
again and you return a view without the checkbox checked.
What you need to do is so set a clicked/checked listener on each list item that will be able to remember when they have been checked. Then when android asks you for a view, you can check if it should be checked or not.
You can see that the getItem
method is already there to help you with this. You could try overriding ArrayAdapter
as that will let you store some simple objects that can hold your 'clicked' state. See: http://developer.android.com/reference/android/widget/ArrayAdapter.html
This is why Aditya asked you where you model class is. Currently you just have a list of students, what you want is a list of students AND whether they have been selected. Maybe a class like this:
class Student
{
private String mName;
public Boolean selected;
public Student(String name)
{
mName = name;
}
public String getName()
{
return mName;
}
}
Then you could have an array of these instead. When an item is clicked, you set selected
on the relevant student item.
Your getView
might look like this:
@Override
public View getView(int position, View convertView, ViewGroup arg2) {
// TODO Auto-generated method stub
ViewHolder viewHolder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item, null);
viewHolder = new ViewHolder();
viewHolder.tvName = (TextView) convertView
.findViewById(R.id.tvItem);
viewHolder.cbName = (CheckBox) convertView
.findViewById(R.id.cbItem);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
Student thisStudent = students[position];
viewHolder.tvName.setText(thisStudent.getName());
if(state || thisStudent.selected){
viewHolder.cbName.setChecked(true);
}else{
viewHolder.cbName.setChecked(false);
}
return convertView;
}
There are lots of guides around about this, here is one such guide that explains how view recycling works in a list (your problem) and also how you can use ArrayAdapter
https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView
Upvotes: 2
Reputation: 1150
If you are using a listView
, your adapter should implement OnCheckedChangeListener
in order to save changes in the checkbox state. In the method that you have to implement onCheckedChanged()
(write it inside getView()) you have to get from SharedPreferences the state of that checkbox and update it.
If you look for this approach you will find some example, here is one
Upvotes: 1
Reputation: 13555
Try to use with RecycleView,
public class CardViewActivity extends ActionBarActivity {
private Toolbar toolbar;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private List<Student> studentList;
private Button btnSelection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
btnSelection = (Button) findViewById(R.id.btnShow);
studentList = new ArrayList<Student>();
for (int i = 1; i <= 15; i++) {
Student st = new Student("Student " + i, "androidstudent" + i
+ "@gmail.com", false);
studentList.add(st);
}
if (toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("Android Students");
}
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
// create an Object for Adapter
mAdapter = new CardViewDataAdapter(studentList);
// set the adapter object to the Recyclerview
mRecyclerView.setAdapter(mAdapter);
btnSelection.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String data = "";
List<Student> stList = ((CardViewDataAdapter) mAdapter)
.getStudentist();
for (int i = 0; i < stList.size(); i++) {
Student singleStudent = stList.get(i);
if (singleStudent.isSelected() == true) {
data = data + "\n" + singleStudent.getName().toString();
/*
* Toast.makeText( CardViewActivity.this, " " +
* singleStudent.getName() + " " +
* singleStudent.getEmailId() + " " +
* singleStudent.isSelected(),
* Toast.LENGTH_SHORT).show();
*/
}
}
Toast.makeText(CardViewActivity.this,
"Selected Students: \n" + data, Toast.LENGTH_LONG)
.show();
}
});
}
For more see this
For ListView see this
Upvotes: 0