滚动时带有复选框的Android ListView会松动选中的项目

Posted

技术标签:

【中文标题】滚动时带有复选框的Android ListView会松动选中的项目【英文标题】:Android ListView with checkboxes loose checked items when scrolling 【发布时间】:2013-09-28 17:38:03 【问题描述】:

我遇到了一个问题,当我滚动列表时,列表视图中的选中项目消失了,我不知道该怎么办。

这是我的自定义适配器代码:

public class SPCKontrola extends Activity 
ArrayList<Integer> yourSelectedItems= new ArrayList<Integer>();

@Override
        public void onResume() 
            super.onResume();

            yourSelectedItems.clear();

        


public class SPCMjereAdapter extends BaseAdapter 
    
        private Context context;

        public SPCMjereAdapter(Context c) 
                   
            context = c;                    
        

        public int getCount() 
            return MyArrList.size();
        

        public Object getItem(int position) 
            return position;
        

        public long getItemId(int position) 
            return position;
        
        public View getView(final int position, View convertView, ViewGroup parent) 

            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            if (convertView == null) 
                convertView = inflater.inflate(R.layout.activity_list_row, null); 

            

            TextView txtOpis = (TextView) convertView.findViewById(R.id.ColOpis); 
            txtOpis.setText(MyArrList.get(position).get("OpisMjere") );

            TextView txtRbMjere = (TextView) convertView.findViewById(R.id.ColCode);
            txtRbMjere.setText(MyArrList.get(position).get("RbMjere"));

            CheckBox Chk = (CheckBox) convertView.findViewById(R.id.ColChk);
            Chk.setTag(MyArrList.get(position).get("RbMjere"));



Chk.setOnCheckedChangeListener(new OnCheckedChangeListener()                
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) 
                        if(isChecked)
                            yourSelectedItems.add(position);
                        else
                            if(yourSelectedItems.contains(position))                                               
                                yourSelectedItems.remove((position));                                   
                            
                        
                    
                    );


            return convertView;

        

我应该在代码中更改或添加什么?我找到了一些示例,但我无法重用它们并在我的代码中实现:/

【问题讨论】:

groups.google.com/forum/#!topic/android-developers/No0LrgJ6q2M。查看 Romain Guy 的评论。 hm... 似乎是一个不错的解决方案,但它扩展了 ListActivity。我试图避免这种情况,因为它会影响到几乎完成的应用程序中的某些内容。 【参考方案1】:

为此,您必须维护一个数组变量yourSelectedItems[] 用于存储您检查过的视图位置。并在您的getView() 方法中添加这样的条件。

if(yourSelectedItems.contains((position)))
    check.setChecked(true);
else
    check.setChecked(false);

您可以通过在 getView().. 中编写此方法来管理您的数组。

 check.setOnCheckedChangeListener(new OnCheckedChangeListener()                
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) 
        if(isChecked)
            yourSelectedItems.add(position);
        else
            if(yourSelectedItems.contains(position))                                               
                yourSelectedItems.remove((position));                                   
            
        
    );

【讨论】:

不幸的是,这不起作用。如果我选择第一个项目而不是向下滚动列表,它会自动检查其他一些项目。如果我回到列表的顶部,第一项在哪里,则不再检查该项目。 它的行为不应该是这样的...你可以发布您更改的代码...?? 我刚刚添加了 ArrayList yourSelectedItems = new ArrayList();并按照您的建议在 getView() 中进行更改。 如果你使用 ArrayList,你必须在各自的位置放置真/假,匹配条件也会不同..所以我们必须为此更改整个代码......而不是你可以使用您的数组列表为整数类型,如下所示... ArrayList yourSelectedItems= new ArrayList();...然后它将起作用... 别担心..即使是经验丰富的 android 开发人员,自定义适配器也会一直困扰着您......让你的新代码有问题..让我看看有什么问题..:)【参考方案2】:

试试这个带有复选框的列表视图示例:http://lalit3686.blogspot.in/2012/06/today-i-am-going-to-show-how-to-deal.html

【讨论】:

【参考方案3】:

为了避免复选框的问题 在 ListView 中,您可以使用 Boolean 数组在开头初始化为假 然后实现 数组中的对应位置 在 ListView 中选中复选框的位置。当您在应用程序中向前和向后移动或滚动 ListView 时,这不会导致复选框的选中状态出现问题。您可以在此处查看示例代码:

Android checkbox multiselected issue

【讨论】:

【参考方案4】:

这发生在我身上,我解决了这个问题,

1.创建一个全局布尔数组列表,并在构造函数上用 MyArrList.size() 填充它。

2.当您更改复选框值时,使用视图索引设置 arratlist。

3.改变这个:

 CheckBox Chk = (CheckBox) convertView.findViewById(R.id.ColChk);
 Chk.setTag(MyArrList.get(position).get("RbMjere"));

用这个:

 CheckBox Chk = (CheckBox) convertView.findViewById(R.id.ColChk);
 Chk.setTag(MyArrList.get(position).get("RbMjere"));
 Chk.setChecked(commentTexts.get(position));

【讨论】:

【参考方案5】:

用这个改变你的 getview()...

     public View getView(final int position, View convertView, ViewGroup parent) 

            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            if (convertView == null) 
                convertView = inflater.inflate(R.layout.activity_list_row, null); 

            

            TextView txtOpis = (TextView) convertView.findViewById(R.id.ColOpis); 
            txtOpis.setText(MyArrList.get(position).get("OpisMjere") );

            TextView txtRbMjere = (TextView) convertView.findViewById(R.id.ColCode);
            txtRbMjere.setText(MyArrList.get(position).get("RbMjere"));

            CheckBox Chk = (CheckBox) convertView.findViewById(R.id.ColChk);


             if(yourSelectedItems.contains((position)))
                Chk.setChecked(true);
             else
                Chk.setChecked(false);
             

            Chk.setOnCheckedChangeListener(new OnCheckedChangeListener()                
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) 
                        if(isChecked)
                            yourSelectedItems.add(position);
                        else
                            if(yourSelectedItems.contains(position))                                               
                                yourSelectedItems.remove((position));                                   
                            
                        
                    
                    );


            return convertView;

        

【讨论】:

不幸的是,这也不起作用...... :(有时会再次丢失检查项目的状态,有时会在 setOnCheckedChangeListener() 内中断 yourSelectedItems.remove((position)) 【参考方案6】:

如果您在 listView.onItemSelectedListner 中使用了 getView,您将面临这个问题 listView 不会将每个对象放在不同的视图中,这就是为什么 当您调用 getView(2) 时,它将返回屏幕上列表的第二个对象的视图而不是列表的第二个对象的视图.. . 你必须在你的类中使用一些布尔值或复选框自己实现它

【讨论】:

【参考方案7】:

我想我得到了一些东西...而不是 Chk.setOnCheckedChangeListener() 我已更改为 Chk.setOnClickListener(new OnClickListener()

public class SPCMjereAdapter extends BaseAdapter 
    
        private Context context;


        public SPCMjereAdapter(Context c) 
                   
            context = c;                    
        

        public int getCount() 
            return MyArrList.size();
        

        public Object getItem(int position) 
            return position;
        

        public long getItemId(int position) 
            return position;
        
        public View getView(final int position, View convertView, ViewGroup parent) 

            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            if (convertView == null) 
                convertView = inflater.inflate(R.layout.activity_list_row, null); 

            

            TextView txtOpis = (TextView) convertView.findViewById(R.id.ColOpis); 
            txtOpis.setText(MyArrList.get(position).get("OpisMjere") );

            TextView txtRbMjere = (TextView) convertView.findViewById(R.id.ColCode);
            txtRbMjere.setText(MyArrList.get(position).get("RbMjere"));

            final CheckBox Chk = (CheckBox) convertView.findViewById(R.id.ColChk);


            if(yourSelectedItems.contains((position)))
                Chk.setChecked(true);
             else
                Chk.setChecked(false);
             

            Chk.setOnClickListener(new OnClickListener() 

                @Override
                public void onClick(View v) 

                    if (Chk.isChecked())
                    
                         yourSelectedItems.add(position);
                     else
                    
                        if(yourSelectedItems.contains(position))                                               
                            yourSelectedItems.remove((position));                                   
                        
                    

                
            );


            return convertView;
        

 

现在向上/向下滚动时可以正常工作。但是还有另一个问题,我有点困惑。滚动和随机检查/取消选中项目时,程序崩溃并且我得到以下错误:

FATAL EXCEPTION: main
java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
at java.util.ArrayList.remove(ArrayList.java:399)
at com.dem.spckontrola.SPCKontrola$SPCMjereAdapter$1.onClick(SPCKontrola.java:830)
at android.view.View.performClick(View.java:4084)
at android.widget.CompoundButton.performClick(CompoundButton.java:100)
at android.view.View$PerformClick.run(View.java:16966)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method

)

好的。我通过添加解决了这个问题 yourSelectedItems.remove(yourSelectedItems.indexOf(position));

所以现在正确的解决方案是:

 public class SPCMjereAdapter extends BaseAdapter 
    
        private Context context;


        public SPCMjereAdapter(Context c) 
                   
            context = c;                    
        

        public int getCount() 
            return MyArrList.size();
        

        public Object getItem(int position) 
            return position;
        

        public long getItemId(int position) 
            return position;
        
        public View getView(final int position, View convertView, ViewGroup parent) 

            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            if (convertView == null) 
                convertView = inflater.inflate(R.layout.activity_list_row, null); 

            

            TextView txtOpis = (TextView) convertView.findViewById(R.id.ColOpis); 
            txtOpis.setText(MyArrList.get(position).get("OpisMjere") );

            TextView txtRbMjere = (TextView) convertView.findViewById(R.id.ColCode);
            txtRbMjere.setText(MyArrList.get(position).get("RbMjere"));

            final CheckBox Chk = (CheckBox) convertView.findViewById(R.id.ColChk);


            if(yourSelectedItems.contains((position)))
                Chk.setChecked(true);
             else
                Chk.setChecked(false);
             

            Chk.setOnClickListener(new OnClickListener() 

                @Override
                public void onClick(View v) 

                    if (Chk.isChecked())
                    
                         yourSelectedItems.add(position);
                     else
                    
                        if(yourSelectedItems.contains(position))                                               
                            yourSelectedItems.remove(yourSelectedItems.indexOf(position));                                   
                        
                    

                
            );


            return convertView;
        

 

但现在我面临新问题:如何获取所有已选中和未选中项目的列表,其中某些复选框(项目)由于列表视图中的许多项目仅在向下滚动时可见而不可见?

【讨论】:

以上是关于滚动时带有复选框的Android ListView会松动选中的项目的主要内容,如果未能解决你的问题,请参考以下文章

滚动自定义 ListView 时,复选框值发生变化

单击按钮时如何在android中获取带有ListView值的复选框,EditText?

当我在 Android 上滚动列表视图时复选框未选中

自定义 listView 行,带有复选框和旋转时的储蓄复选标记

带有复选框和所有可点击的Android ListView [重复]

选中复选框时检查Android listview多个项目