带有复选框的Android列表视图不符合预期

时间:2013-12-02 07:08:59

标签: android listview checkbox adapter recycle

这是关于回收问题。我正在使用自定义适配器来填充列表视图。在自定义行中,有一个图像视图,两个文本框和一个复选框。填充了所有元素,但未正确填充复选框。

getView()内部执行条件,如果条件为真,我将复选框设置为启用状态。这工作正常,但勾选了正确的复选框,还有一些其他复选框也被勾选。我经历了许多堆栈溢出类似的问题,但无法找到答案。非常感谢任何帮助。

以下是我的适配器类:

public class LocationsListAdapter extends BaseAdapter {

    List<Locations> data;
    Context context;
    Locations userSelectedLocation;
    private SharedPreferences locationPreferences;
    private SharedPreferences.Editor locationPrefsEditor;

    public LocationsListAdapter(List<Locations> data, Context c) {
        this.data = data;
        this.context = c;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @SuppressWarnings("static-access")
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {


        ViewHolder holder = null;
        Log.v("ConvertView", String.valueOf(position));

        if (convertView == null) {
            LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = vi.inflate(R.layout.find_your_location_row, null);

            holder = new ViewHolder();
            holder.LocationImage = (SmartImageView) convertView.findViewById(R.id.loca_row_image);
            holder.locationName = (TextView) convertView.findViewById(R.id.txt_loca_name);
            holder.LocationDescription = (TextView) convertView.findViewById(R.id.txt_loca_desc);
            holder.locationCheckText = (TextView) convertView.findViewById(R.id.txt_check);
            holder.locationCheck = (CheckBox) convertView.findViewById(R.id.location_check);
            holder.locationCheck.setOnCheckedChangeListener(myCheckChangList);
            convertView.setTag(holder);

            locationPreferences = context.getSharedPreferences("locationPrefs", context.MODE_PRIVATE);
            locationPrefsEditor = locationPreferences.edit();
            String locationID  = locationPreferences.getString("locationID", "");

            try {
                if(locationID.contains(String.valueOf(data.get(position).getLocationID()))){
                    holder.locationCheck.setChecked(true);
                }
            } catch (Exception e) {
                Log.e("Fatal", " Exception");
            }


             holder.locationCheck.setOnClickListener( new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        userSelectedLocation = data.get(position);
                        locationPreferences = context.getSharedPreferences("locationPrefs", context.MODE_PRIVATE);
                        locationPrefsEditor = locationPreferences.edit();
                        String userSelectedLocationID = userSelectedLocation.getLocationID();
                        locationPrefsEditor.clear();
                        locationPrefsEditor.putString("locationID", userSelectedLocationID);
                        locationPrefsEditor.commit();
                        Intent intent = new Intent(context, HomeScreen.class);
                        context.startActivity(intent);
                        Log.e("Check Box ", "Clicked");
                    }
            });

        }else {
            holder = (ViewHolder) convertView.getTag();
           }

        final Locations location = data.get(position);

        holder.LocationImage.setImageUrl(location.getImagePath());
        holder.locationName.setText(location.getLocationName());
        holder.LocationDescription.setText(location.getLocationDescription());

        return convertView;
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        if (observer != null) {
            super.unregisterDataSetObserver(observer);
        }
    }

    protected class ViewHolder {
        protected SmartImageView LocationImage;
        protected TextView locationName;
        protected TextView LocationDescription;
        protected TextView locationCheckText;
        protected CheckBox locationCheck ;
    }

    OnCheckedChangeListener myCheckChangList = new OnCheckedChangeListener() {
        public void onCheckedChanged(CompoundButton buttonView,
                boolean isChecked) {
            Log.e("checked", "");
        }
    };
}

6 个答案:

答案 0 :(得分:1)

您需要在CheckBox或类似的东西中保存Array状态,以便在检查/取消选中时记住状态,并在getView(...)方法结束时,需要根据数组值设置CheckBox的状态。

查看Checkbox not working properly with ListView链接了解更多详情。

答案 1 :(得分:1)

你必须在开始创建一个数组列表并将状态存储为false

时执行类似的操作
 private ArrayList<Boolean> itemChecked = new ArrayList<Boolean>();    

  for (int i = 0; i < this.getCount(); i++) {
            itemChecked.add(i, false); // initializes all items value with false
        }

每当您点击时只需更改状态并每次都使用更新的值填充列表。

答案 2 :(得分:1)

OnClickListener()仅针对前几个列表项进行声明,并使用相同的&#34;位置&#34;对于所有其他项目。

可以使用的一个选项是,您可以在列表中的每个复选框的标记中设置位置,并从v param中的OnClickListener中获取

答案 3 :(得分:1)

locationPreferences = context.getSharedPreferences("locationPrefs", context.MODE_PRIVATE);
    locationPrefsEditor = locationPreferences.edit();
    String locationID  = locationPreferences.getString("locationID", "");

    try {
        if(locationID.contains(String.valueOf(data.get(position).getLocationID()))){
            holder.locationCheck.setChecked(true);
        }
    } catch (Exception e) {
        Log.e("Fatal", " Exception");
    }

只有convertView == null,才能执行此部分代码。您convertView != null时没有进行setChecked,这意味着当您重复使用视图时,它将无法正确检查

答案 4 :(得分:1)

我相信你的问题在于你的if / else语句。

如果convertView为null,那么您创建一个新视图并使用所有正确的数据填充它,但如果它不是null(即它是一个循环视图),您只需从标记返回完全相同的视图。您没有对有关设置其属性的视图执行任何操作,因此它保持已有的状态(其中一些已被检查)

拥有有效的viewHolder后设置属性。

您目前拥有此模型。

if (convertView == null) {
    //Your code to create the view
    // Your code to set the view properties
}else {
    holder = (ViewHolder) convertView.getTag();
}

将其更改为此(移动将视图属性设置在if / else之外的代码,以便可以为所有视图设置视图属性,无论它们是否被回收。

 if (convertView == null) {
        LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.find_your_location_row, null);

        holder = new ViewHolder();
        holder.LocationImage = (SmartImageView) convertView.findViewById(R.id.loca_row_image);
        holder.locationName = (TextView) convertView.findViewById(R.id.txt_loca_name);
        holder.LocationDescription = (TextView) convertView.findViewById(R.id.txt_loca_desc);
        holder.locationCheckText = (TextView) convertView.findViewById(R.id.txt_check);
        holder.locationCheck = (CheckBox) convertView.findViewById(R.id.location_check);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    Locations location = data.get(position);

    holder.LocationImage.setImageUrl(location.getImagePath());
    holder.locationName.setText(location.getLocationName());
    holder.LocationDescription.setText(location.getLocationDescription());
    boolean ShouldBoxBeChecked = //Insert check for the current box here
    holder.locationCheck.setChecked(ShouldBoxBeChecked);

答案 5 :(得分:1)

在这里,我有一个解决方案。

基本上我已经创建了两个类型字符串的数组列表。当您选中一个复选框时,相应的textview值(或您可以存储到该列表视图项目的任何值)将存储在列表 CHECKEDLIST 中。在另一个列表 ALLVALUES 中,将存储所有值。

在按钮上单击我匹配两个列表,如果匹配发生,那么我从 ALLVALUES 中删除该值并调用notifydatasetchanged

package com.example.test;

import java.io.File;
import java.util.ArrayList;


import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.CompoundButton.OnCheckedChangeListener;

public class MainActivity extends Activity implements OnClickListener {
    private ArrayList<String> checkedIndices = new ArrayList<String>();
    ArrayList<String> list = new ArrayList<String>();
    AScustomadapter adapter;
int count = 0;
private String[] vidNames = {"a","b","c","d","e","f","g","h","i"};
private ListView myList;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button b1 = (Button) findViewById(R.id.button1);
    b1.setOnClickListener(this);



    for (int i = 0; i < vidNames.length; i++) {
        list.add(vidNames[i]);
    }

    myList = (ListView)findViewById(R.id.list);
    adapter = new AScustomadapter(getApplicationContext(), list);
    myList.setAdapter(adapter);
}

@Override
public void onClick(View v) {
    if(v.getId() == R.id.button1) {


        for (int i = 0; i < checkedIndices.size(); i++) {
            for(int j = 0; j <list.size();j++){
            if(list.get(j).contains(checkedIndices.get(i))){
                list.remove(j);
            }
            }
        }
        adapter.notifyDataSetChanged();



    } 

}

public class AScustomadapter extends BaseAdapter {

private ArrayList<String> mListItems;
private LayoutInflater mLayoutInflater;
int i = 0;

public AScustomadapter(Context context, ArrayList<String> arrayList) {
    mListItems = arrayList;
    //get the layout inflater
    mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public int getCount() {
    return mListItems.size();
}

@Override
public Object getItem(int i) {
    return list.get(i);
}

@Override
public long getItemId(int i) {
    return 0;
}

public int getTotalCheckedCount() {
    return checkedIndices.size();
}

@Override
public View getView(final int position, View view, ViewGroup viewGroup) {
    ViewHolder holder;

    if (view == null) {
        holder = new ViewHolder();

        view = mLayoutInflater.inflate(R.layout.list_item, null);
        holder.itemName = (TextView) view.findViewById(R.id.list_item_text_view);
        holder.cb1 = (CheckBox) view.findViewById(R.id.checkBox1);

        view.setTag(holder);
    } else {
        holder = (ViewHolder)view.getTag();
    }

    final String stringItem = mListItems.get(position);

    if (stringItem != null) {
        if (holder.itemName != null) {
            holder.itemName.setText(stringItem);
        }
    }

    holder.cb1.setOnClickListener(new OnClickListener() {

      @Override
      public void onClick(View v) {
                //is chkIos checked?
        if (((CheckBox) v).isChecked()) {
            if(!checkedIndices.contains(getItem(index).toString()))
                checkedIndices.add(getItem(index).toString());          }
        else {
            checkedIndices.remove(getItem(index).toString());

        }
          //case 2

      }
    });

    if(checkedIndices.contains((Integer)position)) {
        holder.cb1.setChecked(true);
    } else {
        holder.cb1.setChecked(false);
    }

    //this method must return the view corresponding to the data at the specified position.
    return view;
}

private class ViewHolder {

    protected TextView itemName;
    protected CheckBox cb1;

}
  }


 }