我有一个带有已检查textview和两个textview的列表视图,但是,我的getView方法在滚动时不断更改listview项,值和复选框状态都保存到sqlite数据库中。我尝试了所有可能的解决方案,花了4个小时试图修复它。 任何帮助表示赞赏。唯一有效的解决方案是在getView()的开头将convertview设置为null,它落后于listview。
目标:正确制作列表视图显示项目而不随意更改其位置。
有需要的人的最终工作代码:
@Override
public View getView( final int position, View convertView, ViewGroup parent) {
viewHolder = null;
if(convertView == null){
convertView = inflater.inflate(R.layout.sin_item,null);
viewHolder = new HolderCo();
viewHolder.box = (CheckBox)convertView.findViewById(R.id.coco);
viewHolder.subject = (TextView)convertView.findViewById(R.id.subject_com);
viewHolder.date = (TextView)convertView.findViewById(R.id.date_co);
convertView.setTag(viewHolder);
}
else{
viewHolder = (HolderCo)convertView.getTag();
}
viewHolder.position = position;
viewHolder.box.setText(list.get(viewHolder.position).getWhats());
viewHolder.subject.setText(list.get(viewHolder.position).getSubject());
if(list.get(viewHolder.position).isSelected()) {
viewHolder.box.setOnCheckedChangeListener(null);
viewHolder.box.setChecked(true);
viewHolder.box.setPaintFlags(viewHolder.box.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}else{
viewHolder.box.setOnCheckedChangeListener(null);
viewHolder.box.setChecked(false);
viewHolder.box.setPaintFlags(viewHolder.box.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
if(dator.equals("d"))
viewHolder.date.setText(list.get(viewHolder.position).getDay()+"/"+list.get(viewHolder.position).getMonth()+"/"+list.get(viewHolder.position).getYear());
if(dator.equals("m"))
viewHolder.date.setText(list.get(viewHolder.position).getMonth()+"/"+list.get(viewHolder.position).getDay()+"/"+list.get(viewHolder.position).getYear());
if(dator.equals("y"))
viewHolder.date.setText(list.get(viewHolder.position).getYear()+"/"+list.get(viewHolder.position).getMonth()+"/"+list.get(viewHolder.position).getDay());
viewHolder.box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.isChecked()) {
list.get(position).setSelected(true);
db.updateState(list.get(position),true);
buttonView.setPaintFlags(buttonView.getPaintFlags()| Paint.STRIKE_THRU_TEXT_FLAG);
if(PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("add_mark_dialog",true))
buttonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialoging(viewHolder.position);
}
});
}else{
buttonView.setOnClickListener(null);
list.get(position).setSelected(false);
db.updateState(list.get(position), false);
buttonView.setPaintFlags(buttonView.getPaintFlags()&(~Paint.STRIKE_THRU_TEXT_FLAG));
}
}
});
return convertView;
}
答案 0 :(得分:1)
通过这样做:
viewHolder.box.setTag(position);
viewHolder.date.setTag(position);
viewHolder.subject.setTag(position);
您将标记设置为视图到创建它们的第一个位置
因此,当使用非空getView()
(之前已回收)调用convertView
时,其viewHolder
中的标记仍然指向该位置。
将这些setTag()
来电移到if()
之外,以便为新回合的视图设置新位置。
BTW我宁愿用
替换所有这些viewHolder.position = position; // outside if()
并在任何地方使用它(整数)x.getTag()
更新:你还必须这样做:
viewHolder.box.setOnCheckedChangeListener(null);
之前:
viewHolder.box.setChecked(...);
因为否则它可以触发你很可能不想要的前一个听众。
答案 1 :(得分:1)
您可以使用if
条件有条件地更新视图。您需要提供相应的else
块,将视图重置为默认值。
例如,
if(dator.equals("d"))
viewHolder.date.setText(...);
if(dator.equals("m"))
viewHolder.date.setText(...);
if(dator.equals("y"))
viewHolder.date.setText(...);
需要像
if(dator.equals("d"))
viewHolder.date.setText(...);
else if(dator.equals("m"))
viewHolder.date.setText(...);
else if(dator.equals("y"))
viewHolder.date.setText(...);
else
viewHolder.date.setText("some default value");
同样重置viewHolder.box.setPaintFlags()
中的默认值。
原因是ListView
次观看次数被回收。回收的观点并不像通货膨胀之后那样处于原始状态。相反,它们将处于它们被回收之前的状态,可能包含先前使用该视图的列表行中的数据。