滚动列表视图 BaseAdapter 上的复选框选中/未选中状态更改
Posted
技术标签:
【中文标题】滚动列表视图 BaseAdapter 上的复选框选中/未选中状态更改【英文标题】:CheckBox checked/unchecked state changes on scroll listview BaseAdapter 【发布时间】:2017-11-17 14:38:47 【问题描述】:我有一些预先选中的复选框的列表视图。当我使用取消选中选中的复选框并再次滚动它时,它会被选中,如果我选中未选中的复选框然后滚动它,它会变为未选中状态。
当我
选中复选框然后滚动它,它会被取消选中
取消选中预先选中的复选框并滚动它,它会被选中
代码:
public class Adapter extends BaseAdapter
private Context activity;
private ArrayList<Data> data;
private static LayoutInflater inflater = null;
private View vi;
TextView roll;
TextView menu;
CheckBox checkBox;
CheckBox cb;
boolean[] checkBoxState;//maintain a local boolean array to store the checked status of checkboxes positionwise
public Adapter(Context context, ArrayList<Data> items)
this.activity = context;
this.data = items;
checkBoxState=new boolean[items.size()];//initializing the local boolean array inside the constructor
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@Override
public int getCount()
return data.size();
@Override
public Object getItem(int i)
return data.get(i);
@Override
public long getItemId(int i)
return i;
@Override
public View getView(final int position, View view, ViewGroup viewGroup)
vi = view;
final int pos = position;
final Data items = data.get(pos);
vi = inflater.inflate(R.layout.list_row, null);
checkBox = (CheckBox) vi.findViewById(R.id.cb);
menu = (TextView) vi.findViewById(R.id.nama_menu);
roll = (TextView) vi.findViewById(R.id.roll);
menu.setText(items.getMenu());
roll.setText(items.getRoll());
if (items.getRoll().equals(items.getRollBlocked()))
checkBox.setChecked(true);
checkBoxState[position] = true;
items.setCheckbox(true);//maintaining boolean check status according to conditions
notifyDataSetChanged();
vi.setEnabled(false);
else if (items.getRoll().equals(items.getRollLate()))
checkBox.setChecked(true);
checkBoxState[position] = true;//maintaining boolean check status according to conditions
items.setCheckbox(true);
notifyDataSetChanged();
vi.setEnabled(false);
else if (items.getRoll().equals(items.getRollCheck()))
checkBox.setChecked(true);
checkBoxState[position] = true;
items.setCheckbox(true);//maintaining boolean check status according to conditions
else if (items.getRollBlocked().equals("-")&& items.getRollCheck().equals("-") && items.getRollLate().equals("-"))
checkBox.setChecked(false);
items.setCheckbox(false);
checkBoxState[position] = false;//maintaining boolean check status according to conditions
checkBox.setChecked(checkBoxState[position]);//checkbox is finally checked depending upon the local boolean array which u just created according to ur needs
vi.setTag(checkBox);
vi.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
final Data items = data.get(pos);
cb = (CheckBox) v.getTag();
if(items.getRoll().equals(items.getRollBlocked()))
if(((CheckBox)v).isChecked())
checkBoxState[position] = true; //explicitly making it true
vi.setEnabled(false);
cb.setChecked(true);
else
checkBoxState[position] = false;//explicitly making it false
else if(items.getRoll().equals(items.getRollLate()))
if(((CheckBox)v).isChecked())
checkBoxState[position] = true; //explicitly making it true
vi.setEnabled(false);
cb.setChecked(true);
else
checkBoxState[position] = false;//explicitly making it false
else if(items.getRoll().equals(items.getRollCheck()))
if(((CheckBox)v).isChecked())
checkBoxState[position] = true; //explicitly making it true
cb.setChecked(false);
items.setCheckbox(false);
else
cb.setChecked(true);
items.setCheckbox(true);
checkBoxState[position] = false;//explicitly making it false
else if (items.getRollBlocked().equals("-") && items.getRollCheck().equals("-") && items.getRollLate().equals("-"))
if(((CheckBox)v).isChecked())
checkBoxState[position] = true; //explicitly making it true
cb.setChecked(false);
items.setCheckbox(false);
else
cb.setChecked(true);
items.setCheckbox(true);
checkBoxState[position] = false;//explicitly making it false
else
);
return vi;
public ArrayList<Data> getAllData()
return data;
Logcat:
FATAL EXCEPTION: main
Process: , PID: 1366
java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
at com.mark_attendance.list.adapter.Adapter.getView(Adapter.java:78)
at android.widget.AbsListView.obtainView(AbsListView.java:2360)
at android.widget.ListView.measureHeightOfChildren(ListView.java:1326)
at android.widget.ListView.onMeasure(ListView.java:1233)
at android.view.View.measure(View.java:19731)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
at android.view.View.measure(View.java:19731)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6120)
at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:714)
at android.support.design.widget.HeaderScrollingViewBehavior.onMeasureChild(HeaderScrollingViewBehavior.java:90)
at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onMeasureChild(AppBarLayout.java:1391)
at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:784)
at android.view.View.measure(View.java:19731)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6120)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:139)
at android.view.View.measure(View.java:19731)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6120)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1464)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:758)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:640)
at android.view.View.measure(View.java:19731)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6120)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:19731)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6120)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1464)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:758)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:640)
at android.view.View.measure(View.java:19731)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6120)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:687)
at android.view.View.measure(View.java:19731)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2271)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1358)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1607)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1246)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6301)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:871)
at android.view.Choreographer.doCallbacks(Choreographer.java:683)
at android.view.Choreographer.doFrame(Choreographer.java:619)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:857)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
数据.java
public class Data
private String roll;
private String menu;
private boolean check;
private String roll_check;
private String roll_blocked;
private String roll_late;
private String studentID;
private int blockedposition;
private int blockedposition2;
public Data()
public Data(String roll,String menu, boolean check,String roll_check,int blockedposition,String roll_blocked,int blockedposition2,String roll_late,String studentID)
this.roll=roll;
this.menu = menu;
this.check = check;
this.roll_check = roll_check;
this.blockedposition=blockedposition;
this.blockedposition2=blockedposition2;
this.roll_blocked=roll_blocked;
this.roll_late=roll_late;
this.studentID=studentID;
public String getRoll()
return roll;
public void setRoll(String roll)
this.roll = roll;
//-----------------------Studentid---------------------------------------
public String getStudentID()
return studentID;
public void setStudentID(String studentID)
this.studentID = studentID;
//--------------------------------------
//------------------------------------------------------------
public int getBlockedPosition()
return blockedposition;
public void setBlockedPosition(int blockedposition)
this.blockedposition = blockedposition;
//------------------------------------------------------------
//------------------------------------------------------------
public int getBlockedPosition2()
return blockedposition2;
public void setBlockedPosition2(int blockedposition2)
this.blockedposition2 = blockedposition2;
//------------------------------------------------------------
public String getRollCheck()
return roll_check;
public void setRollCheck(String roll_check)
this.roll_check = roll_check;
//------------------------------------------------------------
public String getRollBlocked()
return roll_blocked;
public void setRollBlocked(String roll_blocked)
this.roll_blocked = roll_blocked;
//-----------------------LATE-----------------------------------------------------
public String getRollLate()
return roll_late;
public void setRollLate(String roll_late)
this.roll_late = roll_late;
//--------------------------------------------------------------------------
public String getMenu()
return menu;
public void setMenu(String menu)
this.menu = menu;
public boolean isCheckbox()
return check;
public void setCheckbox(boolean check)
this.check = check;
【问题讨论】:
你没有正确维护检查状态 @AvinashRoy 那些预先检查的复选框,就像我检查是否被阻止或延迟时一样,在那个预先检查的复选框被选中并保持它们的状态但是如果我改变任何状态然后滚动然后如果回到它以前的状态 @AvinashRoy 请对此提供帮助 Maintaining checkbox states in listview with CursorAdapter的可能重复 请检查我的答案@ShreyaSrivastava 【参考方案1】:我将尽可能少地更改您的代码。另外,在您根据另一个答案进行更改之前,我从您的上一次修订开始。
但是,您的逻辑可能存在一些问题。您希望根据项目的内容和用户输入来控制复选框。没关系,但你怎么知道使用哪个?我的回答使用内容,直到用户单击该项目,然后从那时起它是手动的。点击后要返回使用内容,需要有一种方法告诉视图返回使用内容。这可能是你对vi.setEnabled()
所做的事情,我不确定。
1st,将它添加到 Data 类中。您可以重新使用您已有的 boolean
变量,但为了安全起见,我刚刚创建了另一个变量。
// add these 4 lines near the top
public static int NO_MANUAL_CHECK = 1;
public static int MANUAL_CHECK_TRUE = NO_MANUAL_CHECK + 1;
public static int MANUAL_CHECK_FALSE = MANUAL_CHECK_TRUE + 1;
int manualCheck;
// and the getter & setter
public int isManualCheck()
return manualCheck;
public void setManualCheck(int check)
this.manualCheck = check;
这是getView()
方法,包括OnClickListener()
。
@Override
public View getView(final int position, View view, ViewGroup viewGroup)
vi = view;
final int pos = position;
final Data items = data.get(pos);
vi = inflater.inflate(R.layout.list_row, null);
checkBox = (CheckBox) vi.findViewById(R.id.cb);
menu = (TextView) vi.findViewById(R.id.nama_menu);
roll = (TextView) vi.findViewById(R.id.roll);
menu.setText(items.getMenu());
roll.setText(items.getRoll());
if(items.manualCheck == Data.NO_MANUAL_CHECK)
if (items.getRoll().equals(items.getRollBlocked()))
checkBox.setChecked(true);
items.setCheckbox(true);//maintaining boolean check status according to conditions
notifyDataSetChanged();
//vi.setEnabled(false);
else if (items.getRoll().equals(items.getRollLate()))
checkBox.setChecked(true);
items.setCheckbox(true);
notifyDataSetChanged();
//vi.setEnabled(false);
else if (items.getRoll().equals(items.getRollCheck()))
checkBox.setChecked(true);
items.setCheckbox(true);//maintaining boolean check status according to conditions
else /*** notice here I've changed this condition to account for unknown content of item ***/
checkBox.setChecked(false);
items.setCheckbox(false);
else
boolean manualChecked = (items.isManualCheck() == Data.MANUAL_CHECK_TRUE);
checkBox.setChecked(manualChecked);
vi.setTag(checkBox);
vi.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Log.d("TAG", "pos = " + pos);
final Data items = data.get(pos);
cb = (CheckBox) v.getTag();
// toggle manual check
if(items.isManualCheck() == Data.MANUAL_CHECK_TRUE)
items.setManualCheck(Data.MANUAL_CHECK_FALSE);
else
items.setManualCheck(Data.MANUAL_CHECK_TRUE);
// you don't need to do all the display logic again, just tell the Adapter & getView() will be called
notifyDataSetChanged();
);
return vi;
一般来说,有一些事情会以另一种方式更好。在您的getView()
中,您每次都会放大视图。请参阅ListView 了解更有效的方法。此外,将OnItemClickListener()
用于ListView 更为常见。如果您为 ListView 使用 ViewHolder,那么 onClickListener()
会更好。无论如何,我不想对您的代码进行太多更改。我希望这能解决您的问题。
【讨论】:
我会在实施您的解决方案后通知您 预检查的条件如果rollnumber等于blocked它应该是检查没有发生它不自动检查复选框我的条件如下link【参考方案2】:尝试这样做,请阅读我试图详细解释的 cmets: 在您的数据类中,只需添加此布尔标志,这将是选中或未选中将依赖的主要标志:
public class Data
private String roll;
private String menu;
private boolean check;
private String roll_check;
private String roll_blocked;
private String roll_late;
private String studentID;
public boolean isBoolStorage()
return boolStorage;
public void setBoolStorage(boolean boolStorage)
this.boolStorage = boolStorage;
private boolean boolStorage;//Boolean flag is maintained at object level with getters and setters
private int blockedposition;
private int blockedposition2;
public Data()
public Data(String roll,String menu, boolean check,String roll_check,int blockedposition,String roll_blocked,int blockedposition2,String roll_late,String studentID)
this.roll=roll;
this.menu = menu;
this.check = check;
this.roll_check = roll_check;
this.blockedposition=blockedposition;
this.blockedposition2=blockedposition2;
this.roll_blocked=roll_blocked;
this.roll_late=roll_late;
this.studentID=studentID;
public String getRoll()
return roll;
public void setRoll(String roll)
this.roll = roll;
//-----------------------Studentid---------------------------------------
public String getStudentID()
return studentID;
public void setStudentID(String studentID)
this.studentID = studentID;
//--------------------------------------
//------------------------------------------------------------
public int getBlockedPosition()
return blockedposition;
public void setBlockedPosition(int blockedposition)
this.blockedposition = blockedposition;
//------------------------------------------------------------
//------------------------------------------------------------
public int getBlockedPosition2()
return blockedposition2;
public void setBlockedPosition2(int blockedposition2)
this.blockedposition2 = blockedposition2;
//------------------------------------------------------------
public String getRollCheck()
return roll_check;
public void setRollCheck(String roll_check)
this.roll_check = roll_check;
//------------------------------------------------------------
public String getRollBlocked()
return roll_blocked;
public void setRollBlocked(String roll_blocked)
this.roll_blocked = roll_blocked;
//-----------------------LATE-----------------------------------------------------
public String getRollLate()
return roll_late;
public void setRollLate(String roll_late)
this.roll_late = roll_late;
//--------------------------------------------------------------------------
public String getMenu()
return menu;
public void setMenu(String menu)
this.menu = menu;
public boolean isCheckbox()
return check;
public void setCheckbox(boolean check)
this.check = check;
现在通过运行基本的 for-each 循环并根据您的条件设置布尔状态,根据您的条件修改您的数据集: 假设你的数据集是 ArrayList 数据;
循环遍历数据集并在条件成功时放置布尔标志
for(Data data :datas)
if (data.getRoll().equals(data.getRollBlocked()))
data.setBoolStorage(true);//setting flags to true and false respectively according to conditions and modifying basic data set before sending it to the adapter
else if (data.getRoll().equals(data.getRollLate()))
data.setBoolStorage(true);
else if (data.getRoll().equals(data.getRollCheck()))
data.setBoolStorage(true);
else if (data.getRollBlocked().equals("-")&& data.getRollCheck().equals("-") && data.getRollLate().equals("-"))
data.setBoolStorage(false);
//Now call ur adapter with modified data set
Adapter adapter = new Adapter(MainActivity.this,datas);
你的适配器类,你必须这样写:
private Context activity;
private ArrayList<Data> data;
private static LayoutInflater inflater = null;
private View vi;
TextView roll;
TextView menu;
CheckBox checkBox;
CheckBox cb;
boolean[] checkBoxState;//maintain a local boolean array to store the checked status of checkboxes positionwise
public Adapter(Context context, ArrayList<Data> items)
this.activity = context;
this.data = items;
checkBoxState=new boolean[data.size()];//initializing the local boolean array inside the constructor
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@Override
public int getCount()
return data.size();
@Override
public Object getItem(int i)
return data.get(i);
@Override
public long getItemId(int i)
return i;
@Override
public View getView(final int position, View view, ViewGroup viewGroup)
vi = view;
final int pos = position;
final Data items = data.get(pos);
vi = inflater.inflate(R.layout.list_row, null);
checkBox = (CheckBox) vi.findViewById(R.id.cb);
menu = (TextView) vi.findViewById(R.id.nama_menu);
roll = (TextView) vi.findViewById(R.id.roll);
menu.setText(items.getMenu());
roll.setText(items.getRoll());
if (items.isBoolStorage())
checkBox.setChecked(true);
checkBoxState[position] = true;
items.setCheckbox(true);//maintaining boolean check status according to conditions
vi.setEnabled(false);
else if (items.isBoolStorage())
checkBox.setChecked(true);
checkBoxState[position] = true;//maintaining boolean check status according to conditions
items.setCheckbox(true);
vi.setEnabled(false);
else if (items.isBoolStorage())
checkBox.setChecked(true);
checkBoxState[position] = true;
items.setCheckbox(true);//maintaining boolean check status according to conditions
else if (!items.isBoolStorage())
checkBox.setChecked(false);
items.setCheckbox(false);
checkBoxState[position] = false;//maintaining boolean check status according to conditions
checkBox.setChecked(checkBoxState[position]);//checkbox is finally checked depending upon the local boolean array which u just created according to ur needs
vi.setTag(checkBox);
vi.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
final Data items = data.get(pos);
cb = (CheckBox) v.getTag();
if(items.getRoll().equals(items.getRollBlocked()))
if(((CheckBox)v).isChecked())
checkBoxState[position] = true; //explicitly making it true
items.setBoolStorage(true);// changing boolean flag of the object accordingly
vi.setEnabled(false);
cb.setChecked(true);
else
items.setBoolStorage(false);
checkBoxState[position] = false;//explicitly making it false
else if(items.getRoll().equals(items.getRollLate()))
if(((CheckBox)v).isChecked())
checkBoxState[position] = true; //explicitly making it true
items.setBoolStorage(true);
vi.setEnabled(false);
cb.setChecked(true);
else
items.setBoolStorage(false);
checkBoxState[position] = false;//explicitly making it false
else if(items.getRoll().equals(items.getRollCheck()))
if(((CheckBox)v).isChecked())
items.setBoolStorage(false);
checkBoxState[position] = false; //explicitly making it true
cb.setChecked(false);
items.setCheckbox(false);
else
items.setBoolStorage(true);
cb.setChecked(true);
items.setCheckbox(true);
checkBoxState[position] = true;//explicitly making it true
else if (items.getRollBlocked().equals("-") && items.getRollCheck().equals("-") && items.getRollLate().equals("-"))
if(((CheckBox)v).isChecked())
checkBoxState[position] = false; //explicitly making it true
items.setBoolStorage(false);
cb.setChecked(false);
items.setCheckbox(false);
else
items.setBoolStorage(true);
cb.setChecked(true);
items.setCheckbox(true);
checkBoxState[position] = true;//explicitly making it false
else
);
return vi;
public ArrayList<Data> getAllData()
return data;
【讨论】:
它在此显示红色下划线(vi.checkBox.setChecked(checkBoxState[position]);) 显示-->无法解析符号'checkBox'并且在此(checkBoxState[position] = true; ) 它显示 ------>从内部类中访问变量“位置”,需要声明为 final 按 alt+enter 会使位置变量最终化 它在 vi.checkBox.setChecked(checkBoxState[position]) 中显示错误;说----->无法解析符号'checkBox' 我不知道你的变量名你必须根据你的变量名进行更改,这些小事情我希望你至少能解决 这是我粘贴的整个类代码,但它没有使用 vi 复选框。【参考方案3】:只需尝试从if
子句中删除checkBox.setChecked()
并将其设置为checkBox.setChecked(items.getRoll().equals(items.getRollLate()))
。它应该可以完成这项工作。
【讨论】:
【参考方案4】:我在您的代码中看到的问题是您没有以标准方式制作适配器。检查此代码,以这种方式制作您的适配器,或者更好地将您的代码复制并粘贴到此类中。它会正常工作的。
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
/**
* Created by Zohaib Hassan on 11/28/2016.
*/
public class InboxAdapter extends ArrayAdapter<InboxRow>
ArrayList<InboxRow> items;
Context context;
public InboxAdapter(Context context, int resource, ArrayList<InboxRow> items)
super(context , resource , items);
this.context = context;
this.items = items;
@Override
public View getView(int position, View convertView, ViewGroup parent)
// Get the data item for this position
InboxRow rowItem = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
ViewHolder viewHolder; // view lookup cache stored in tag
if (convertView == null)
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.inbox_row, null);
viewHolder.tvUserName = (TextView) convertView.findViewById(R.id.tv_user_name_inbox);
viewHolder.tvMessage = (TextView) convertView.findViewById(R.id.tv_message_inbox);
viewHolder.tvTimeCount = (TextView) convertView.findViewById(R.id.tv_time_count_inbox);
viewHolder.userProfilePic = (CircleImageView) convertView.findViewById(R.id.inbox_profile_image);
convertView.setTag(viewHolder);
else
viewHolder = (ViewHolder) convertView.getTag();
// Set Your data here!
return convertView;
private static class ViewHolder
TextView tvUserName , tvMessage , tvTimeCount;
CircleImageView userProfilePic;
这个 Adapter 的主要部分是 ViewHolder 类,ViewHolder 类将确保您的数据数组的值不会相互混淆。
【讨论】:
【参考方案5】:在适配器类中重写此方法
@Override
public int getItemViewType(int position)
return position;
【讨论】:
以上是关于滚动列表视图 BaseAdapter 上的复选框选中/未选中状态更改的主要内容,如果未能解决你的问题,请参考以下文章
当我滚动列表视图单选按钮被自动选择或取消选择无法保持单选按钮的状态