滚动自定义列表视图时,复选框值会更改




我有什么:带有文本视图和复选框的自定义列表视图。


问题:假设我的屏幕一次只能显示 6 项列表,其他项是不可见的。所以我检查了列表中的第一个元素(位置为 0 的项目)。我向下滚动以查看所有列表,当我在第一个元素(位置 0 的项目)向上滚动时,复选框被正确选中。伟大!但是现在也有新项目被选中,例如位置 8 的项目(因为当我滚动列表(对于 theRycicling)时,它变成了位置 0 的新项目..记住我的屏幕一次只显示 7 个元素)。它被检查了,但我从来没有检查过!

问题:如何避免此问题?我不希望我不单击的复选框更改其状态。
在我的适配器下面 listView 与 getView 函数,我已经在其中实现了 setOnCheckedChangeListener:
public class NewQAAdapterSelectFriends extends BaseAdapter {
private LayoutInflater mInflater;
private Person[] data;

public NewQAAdapterSelectFriends(Context context) { 
    mInflater = LayoutInflater.from(context);
}
public void setData(Person[] data) {
    this.data = data;
}
@Override
public int getCount() {
    return data.length;
}
@Override
public Object getItem(int item) {
    return data[item];
}
@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.item_select_friends, null);
        final ViewHolder viewHolder = new ViewHolder();
        viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
        viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
        viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
        viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
        convertView.setTag(viewHolder);
        viewHolder.nameText.setTag(viewHolder.nameText);
        viewHolder.nameText.setTag(viewHolder.surnameText);
        viewHolder.contactImage.setTag(data[position]);
        viewHolder.checkBox.setOnCheckedChangeListener(
                new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
                        Person element = (Person) viewHolder.checkBox.getTag();
                        if(isChecked){
                            element.setCheck(buttonView.isChecked());
                            //data[position].setCheck(true); //this is equivalent to previous line
                        }
                        else{
                            //to-do
                        }
                    }
                });
        viewHolder.checkBox.setTag(data[position]);
    } else {

    }
     ViewHolder holder = (ViewHolder) convertView.getTag();
     holder.nameText.setText(data[position].getName());
     holder.surnameText.setText(data[position].getSurname());
     holder.contactImage.setImageResource(data[position].getPhotoRes());
     holder.contactImage.setScaleType(ScaleType.FIT_XY);
     holder.checkBox.setChecked(data[position].isCheck());
    return convertView;
}
static class ViewHolder {
    TextView nameText;
    TextView surnameText;
    ImageView contactImage;
    CheckBox checkBox;
}
}

感谢您的回答:)

编辑:根据建议,我更改了我的getView,如下所示:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder viewHolder;
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.item_select_friends, null);
        viewHolder=new ViewHolder();
        viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
        viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
        viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
        viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
        convertView.setTag(viewHolder);
        viewHolder.nameText.setTag(viewHolder.nameText);
        viewHolder.nameText.setTag(viewHolder.surnameText);
        viewHolder.contactImage.setTag(data[position]);
        viewHolder.checkBox.setChecked(data[position].isCheck());  
        viewHolder.checkBox.setOnClickListener(new OnClickListener() {  
            public void onClick(View arg0) {  
                if(viewHolder.checkBox.isChecked()==true)   
                    data[position].setCheck(true);  
                else  
                    data[position].setCheck(false);  
            }  
        }); 
    }
    else{
        viewHolder = (ViewHolder) convertView.getTag();
    }
    viewHolder.nameText.setText(data[position].getName());
    viewHolder.surnameText.setText(data[position].getSurname());
    viewHolder.contactImage.setImageResource(data[position].getPhotoRes());
    viewHolder.contactImage.setScaleType(ScaleType.FIT_XY);
    viewHolder.checkBox.setChecked(data[position].isCheck());
    return convertView;
}

编辑后的情况: 现在,如果我检查屏幕上显示的初始项目,然后我搜索列表,则它们的值已正确保存。但是当我滚动列表时,例如我想检查列表的最后一棵树复选框,然后在我滚动后它们变得未选中......但是为什么??????

解决:我用这段代码解决了我的getView问题:

    public class NewQAAdapterSelectFriends extends BaseAdapter {
private LayoutInflater mInflater;
private Person[] data;
boolean[] checkBoxState;
ViewHolder viewHolder;
public NewQAAdapterSelectFriends(Context context) { 
    mInflater = LayoutInflater.from(context);
}

public void setData(Person[] data) {
    this.data = data;
    checkBoxState=new boolean[data.length];
}
@Override
public int getCount() {
    return data.length;
}
@Override
public Object getItem(int item) {
    return data[item];
}
@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.item_select_friends, null);
        viewHolder=new ViewHolder();
        viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
        viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
        viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
        viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
        convertView.setTag(viewHolder);
    }
    else{
        viewHolder = (ViewHolder) convertView.getTag();
    }
    viewHolder.nameText.setText(data[position].getName());
    viewHolder.surnameText.setText(data[position].getSurname());
    viewHolder.contactImage.setImageResource(data[position].getPhotoRes());
    viewHolder.contactImage.setScaleType(ScaleType.FIT_XY);
    viewHolder.checkBox.setChecked(checkBoxState[position]);
    viewHolder.checkBox.setOnClickListener(new View.OnClickListener() {
           public void onClick(View v) {
               if(((CheckBox)v).isChecked()){
                   checkBoxState[position]=true;
                   data[position].setCheck(true);
               }else{
                   checkBoxState[position]=false;
                   data[position].setCheck(false);
               }
            }
        });
    return convertView;
}

static class ViewHolder {
    TextView nameText;
    TextView surnameText;
    ImageView contactImage;
    CheckBox checkBox;
}

}

我已经看过本教程来做我的getView:http://androidcocktail.blogspot.it/2012/04/adding-checkboxes-to-custom-listview-in.html

我解决了我的问题,只是将"setOnCheckedChangeListener"更改为"setOnClickListener"

public View getView(final int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        CheckBox cbItemChecklist = new CheckBox(context);
        holder = new ViewHolder();
        holder.cbItemChecklist = cbItemChecklist;
        convertView = cbItemChecklist;
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }
    final ItemChecklist itemChecklist = itensChecklist.get(position);
    holder.cbItemChecklist.setText(itemChecklist
            .getDescricaoItemChecklist());
    holder.cbItemChecklist.setChecked(itemChecklist.isChecked());
    holder.cbItemChecklist
            .setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(itemChecklist.isChecked()){
                        itemChecklist.setChecked(false);
                    } else {
                        itemChecklist.setChecked(true);                         
                    }

                }
            });
    return convertView;
}

检查下面的代码 -

public View getView(int position, View convertView, ViewGroup parent){
            View view = convertView;
            ViewHolder holder = new ViewHolder();
            if(view == null){
                view = inflater.inflate(R.layout.list_callcycle_blue, null);                
                holder.llContainer = (LinearLayout) view.findViewById(R.id.ll_container);
                holder.lblLabel = (TextView) view.findViewById(R.id.txt_desc);
                holder.cb = (CheckBox) view.findViewById(R.id.cb_store);
                view.setTag(holder);
            } else {
                holder = (ViewHolder) view.getTag();
            }
            final Object data = getItem(position);
            holder.lblLabel.setText(data.getDescription());
            holder.cb.setTag(position);
            holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    int position = (Integer) buttonView.getTag();
                    objects.get(position).setChecked(buttonView.isChecked());
                }
            });
            holder.cb.setChecked(isChecked(position));
            return view;
        }

始终记住,使用更改holder.cb.setOnCheckedChangeListener()即任何侦听器在设置数据之前,在我们的例子中它是holder.cb.setChecked()

原因 :当我们滚动时,listview 将回收视图,因此如果在侦听器之前使用 setcheck,那么它将根据旧侦听器选择值。如果我们在侦听器之后设置它,那么它将采用最新值

仅当转换视图为空时,您才设置复选框的标签。这仅适用于记录的第一个屏幕。当用户向下滚动时,以前的转换视图将被回收。因此,您的复选框将较旧的数据项作为其标记。

选中的更改侦听器应如下所示:

new CompoundButton.OnCheckedChangeListener()
{
    @Override
    public void onCheckedChanged(CompoundButton buttonView,boolean isChecked)
    {
        Person element = (Person) viewHolder.checkBox.getTag();
        data[position].setCheck(isChecked);
        if(isChecked)
        {
            // do your stuff
        }
        else
        {
            //to-do
        }
    }
}

您没有涵盖 convertView != null 的情况,这是上下滚动时发生的情况。您应该实现一种方法来回收转换视图(更好),或者只是忽略它并在这种情况下也提供新的视图(更糟)。

检查此代码

public class NewQAAdapterSelectFriends extends BaseAdapter {
private LayoutInflater mInflater;
private Person[] data;
ArrayList<String> checkedItem=new ArrayList<String>();
public NewQAAdapterSelectFriends(Context context) { 
    mInflater = LayoutInflater.from(context);
}
public void setData(Person[] data) {
    this.data = data;
}
@Override
public int getCount() {
    return data.length;
}
@Override
public Object getItem(int item) {
    return data[item];
}
@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.item_select_friends, null);
        final ViewHolder viewHolder = new ViewHolder();
        viewHolder.nameText=(TextView) convertView.findViewById(R.id.personName);
        viewHolder.surnameText=(TextView) convertView.findViewById(R.id.personSurname);
        viewHolder.contactImage=(ImageView) convertView.findViewById(R.id.personImage);
        viewHolder.checkBox=(CheckBox)convertView.findViewById(R.id.checkBox);
        convertView.setTag(viewHolder);
        viewHolder.nameText.setTag(viewHolder.nameText);
        viewHolder.nameText.setTag(viewHolder.surnameText);
        viewHolder.contactImage.setTag(data[position]);
        viewHolder.checkBox.setOnCheckedChangeListener(
                new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
                        Person element = (Person) viewHolder.checkBox.getTag();
                        if(isChecked){
                            getCheckList(data[position],isChecked);
                        }
                        else{
                            getCheckList(data[position],isChecked);    
                        }
                    }
                });
        viewHolder.checkBox.setTag(data[position]);
    } 
     ViewHolder holder = (ViewHolder) convertView.getTag();
     holder.nameText.setText(data[position].getName());
     holder.surnameText.setText(data[position].getSurname());
     holder.contactImage.setImageResource(data[position].getPhotoRes());
     holder.contactImage.setScaleType(ScaleType.FIT_XY);
     if(checkedItem != null && checkedItem.contains(data[position])){
        viewHolder.checkBox.setChecked(true);
     }else
     {
        viewHolder.checkBox.setChecked(false);
     } 
    return convertView;
}
static class ViewHolder {
    TextView nameText;
    TextView surnameText;
    ImageView contactImage;
    CheckBox checkBox;
}
public void getCheckList(String value,boolean status){
        if(!checkedItem.contains(value)  && status)
        {
            checkedItem.add(value);
        }
        if(checkedItem.contains(value)  && !status)
        {
            checkedItem.remove(value);
        }
    }
}

我有一个很好的复选框选择。您可以将android:state_activated="true"用于列表视图行。它不会丢失其状态,也不需要大量代码。

这是工作方法

  • 在可绘制对象文件夹中创建active_row.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:state_activated="true"        
          android:drawable="@android:color/darker_gray"/>
 </selector>   
  • 将行布局的背景设置为android:background="@drawable/active_row.xml"
  • 最后将其添加到您的列表视图中 android:choiceMode="multipleChoice"

您可以像这样检查每一行的状态

View v;
LinearLayout yourRowLayout;
for (int i = 0; i < yourListView.getChildCount(); i++) {
v = yourListView.getChildAt(i);
yourRowLayout = (LinearLayout) v.findViewById(R.id. yourRowLayout);
if(yourRowLayout.isActivated()){....  }  }

在适配器中使用 setTag()。您可以在此处查看示例 带有复选框滚动问题的示例列表视图

您需要更新适配器以保留复选框的值

holder.chk.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                CheckBox c = (CheckBox)v.findViewById(R.id.chkID);
                Boolean chk = c.isChecked();
                Integer pos = (Integer)v.getTag();
                itemList.get(pos).setChk(chk);
            }
        });

如需更多帮助,请参阅保留复选框值中的这篇文章

最新更新