我有一个ListView,它使用自定义适配器,如下所示:
private class CBAdapter extends BaseAdapter implements OnCheckedChangeListener{
Context context;
public String[] englishNames;
LayoutInflater inflater;
CheckBox[] checkBoxArray;
LinearLayout[] viewArray;
private boolean[] checked;
public CBAdapter(Context con, String[] engNames){
context=con;
englishNames=engNames;
inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
checked= new boolean[englishNames.length];
for(int i=0; i<checked.length; i++){
checked[i]=false;
//Toast.makeText(con, checked.toString(),Toast.LENGTH_SHORT).show();
}
checkBoxArray = new CheckBox[checked.length];
viewArray = new LinearLayout[checked.length];
}
public int getCount() {
return englishNames.length;
}
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
if(viewArray[position] == null){
viewArray[position]=(LinearLayout)inflater.inflate(R.layout.record_view_start,null);
TextView tv=(TextView)viewArray[position].findViewById(R.id.engName);
tv.setText(englishNames[position]);
checkBoxArray[position]=(CheckBox)viewArray[position].findViewById(R.id.checkBox1);
}
checkBoxArray[position].setChecked(checked[position]);
checkBoxArray[position].setOnCheckedChangeListener(this);
return viewArray[position];
}
public void checkAll(boolean areChecked){
for(int i=0; i<checked.length; i++){
checked[i]=areChecked;
if(checkBoxArray[i] != null)
checkBoxArray[i].setChecked(areChecked);
}
notifyDataSetChanged();
}
public void onCheckedChanged(CompoundButton cb, boolean isChecked) {
for(int i=0; i<checked.length; i++){
if(cb == checkBoxArray[i])
checked[i]=isChecked;
}
}
public boolean itemIsChecked(int i){
return checked[i];
}
}
布局相当简单,所以我不会发布它们,除非有人认为它们是相关的。
问题是某些CheckBox没有响应。它似乎是首次显示布局时可见的。任何你必须向下滚动按预期工作。
任何指示赞赏。
答案 0 :(得分:15)
您的答案中的代码有效,但效率低下(您实际上可以看到这一点,只需滚动ListView
并检查Logcat
以查看垃圾收集器是否正常工作)。将回收视图的改进的getView
方法如下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout view = (LinearLayout) convertView;
if (view == null) {
view = (LinearLayout) inflater.inflate(R.layout.record_view_start, parent, false);
}
TextView tv = (TextView) view.findViewById(R.id.engName);
tv.setText(getItem(position));
CheckBox cBox = (CheckBox) view.findViewById(R.id.checkBox1);
cBox.setTag(Integer.valueOf(position)); // set the tag so we can identify the correct row in the listener
cBox.setChecked(mChecked[position]); // set the status as we stored it
cBox.setOnCheckedChangeListener(mListener); // set the listener
return view;
}
OnCheckedChangeListener mListener = new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mChecked[(Integer)buttonView.getTag()] = isChecked; // get the tag so we know the row and store the status
}
};
关于你的问题的代码,起初我认为这是错误的,因为你设置行的方式,但我不明白为什么适配器将具有该行为,因为你从列表中分离行视图。此外,我甚至测试了代码,它在CheckBoxes
上工作得很好(但内存处理非常糟糕)。也许你正在做其他让适配器无法工作的东西?
答案 1 :(得分:1)
首先我要说你已经抛弃了使用适配器的一个主要好处:可重用的视图。对每个创建的View
持有一个硬引用会很有可能达到内存上限。如果convertView
为非空,则应重复使用convertView
,并在OnClickListener
为空时创建视图。有很多教程可以告诉你如何做到这一点。
适配器中使用的视图通常由父View
附加OnItemClickListener
,以便您可以在ListView
上设置android:clickable="true"
。这将取代个人观点上的任何触摸听众。尝试在XML中的CheckBox
上设置{{1}}。
答案 2 :(得分:0)
这可能不是最优雅或最有效的解决方案,但它适用于我的情况。出于某种原因,尝试从视图数组或使用convertView重用视图会使每个事情变得不稳定并且CheckBoxes无法响应。
唯一有效的方法是在每次调用getView()时创建一个新的视图。
public View getView(final int position, View convertView, ViewGroup parent) {
LinearLayout view;
view=(LinearLayout)inflater.inflate(R.layout.record_view_start,null);
TextView tv=(TextView)view.findViewById(R.id.engName);
tv.setText(englishNames[position]);
CheckBox cBox=(CheckBox)view.findViewById(R.id.checkBox1);
cBox.setChecked(checked[position]);
cBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
checked[position]=isChecked;
}
});
return view;
}
我正在调用一个单独定义的onCheckedChangedListener,然后通过id识别哪个CheckBox,而不是为每个CheckBox设置一个新的侦听器,这也阻碍了找到这个解决方案。
到目前为止,我还没有将此标记为正确的答案,因为我希望其他人可能会对每次相当浪费的重建视图提出一些意见。