5

我所拥有的:带有 Textviews 和复选框的自定义列表视图。
问题:如果我检查屏幕上显示的初始项目,然后滚动列表,当我返回列表顶部(向上滚动)时,它们的值被正确保存。但是,如果我滚动列表,例如我想检查列表的最后一个树复选框,那么如果我向上和向下滚动它们就会被取消选中....为什么?**
我在其他论坛上看到了相同问题的各种解决方案也在stackoverflow上,但问题仍然存在。
在我认为可以的 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

4

3 回答 3

2

即使在方法中使用new创建类时,也为变量创建了不同的范围。换句话说:

// Creating a new scope here -->       vvv
viewHolder.checkBox.setOnClickListener(new OnClickListener() {
    // Any variables not visible to the entire class, won't work properly in here! 
    //  (variables like: viewHolder, position, possibly data) 
    public void onClick(View arg0) {  
        if(viewHolder.checkBox.isChecked()==true)   
            data[position].setCheck(true);  
        else  
            data[position].setCheck(false);  
    }  
}); // Exited "new class'" scope

position和你想的不一样position。尝试保存position可以再次引用它的值:

viewHolder.checkBox = (CheckBox) convertView.findViewById(R.id.checkBox);
viewHolder.position = position;
convertView.setTag(viewHolder);
...

viewHolder.checkBox.setOnClickListener(new OnClickListener() {  
    public void onClick(View view) {
        ViewHolder viewHolder = (ViewHolder) view.getTag();
        data[viewHolder.position].setCheck(viewHolder.checkBox.isChecked());   
    }  
}); 

由于您正在处理 CheckBox ,但我建议您使用OnCheckedChangeListener

但是,如果您更改ChoiceMode,您可能不需要为 ListView 行定义任何侦听器:

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
于 2012-07-05T20:39:55.223 回答
0

也加viewHolder.checkBox.setChecked(checkBoxState[position]);viewHolder.checkBox.setOnCheckedChangedListeneror之后viewHolder.checkBox.setOnClickListener

因为滚动后,当 listview 回收它的视图时,它将setChecked在旧监听器的基础上使用,这在某些情况下可能会丢失值。

所以这是流程 -

getView()
---
---
---
viewHolder.checkBox.setOnCheckedChangedListener()
---
---
---
viewHolder.checkBox.setChecked()
于 2015-01-20T09:10:41.687 回答
0
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>
{
    boolean[] checkBoxState;


    public MyAdapter(Context context, ArrayList<String> list ) {
        checkBoxState = new boolean[list.size()];
    }

    @Override
    public void onBindViewHolder( final ViewHolder holder,  final int position) {
        holder.checkBox.setTag(position); 

            holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
                @Override
                public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                    if(compoundButton.isPressed()) // check whether user pressed the checkbox.
                    {
                        int getPosition = (Integer) compoundButton.getTag();  // Here we get the position that we have set for the checkbox using setTag.
                        checkBoxState[getPosition] = compoundButton.isChecked(); // Set the value of checkbox to maintain its state.
                    }
                }
            });

            holder.checkBox.setChecked(checkBoxState[position]);
    }   

    public class ViewHolder extends RecyclerView.ViewHolder  {
        public CheckBox checkBox;
        public ViewHolder(View v,MainActivity mainActivity) {
            super(v);
            checkBox= (CheckBox) v.findViewById(R.id.checkBox);
        }
    }

    @Override
    public int getItemCount() {
        return list.size();
    }
}

滚动时,可能会自动调用 onCheckedChanged() 方法。因此,您可能需要 isPressed() 方法来检查用户是否按下了复选框。我的适配器类如上所示。请注意,当您向列表中添加新元素时,您应该更新布尔数组 checkBoxState,例如,当您向列表中添加元素时,您应该调用以下命令:

checkBoxState = new boolean[list.size()+1];

或者使用一个数组列表来保存布尔变量并将元素添加到这个数组列表中,无论你想要什么。

我还为此解决方案实施了一个项目。您可以从这里下载: https ://www.dropbox.com/s/ssm58w62gw32i29/recyclerView_checkbox_highlight.zip?dl=0

截图如下:

屏幕1 屏幕2 屏幕3 屏幕4

于 2017-10-07T20:31:45.257 回答