通过列表视图检查动态生成的复选框时出现问题 [英] Getting an issue while checking the dynamically generated checkbox through list view

查看:32
本文介绍了通过列表视图检查动态生成的复选框时出现问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道其他成员已经问过这个问题,一些成员也给出了解决方案,但问题是我没有找到任何适合我的应用程序的解决方案.我正在创建一个应用程序,其中我有一个屏幕,该屏幕将显示带有列表项、复选框和三个文本视图的动态列表视图(一个用于候选名称,另外两个用于时钟输入和时钟输出时间,它们将在选择日期和时间后显示)日期时间选择器.现在我的问题是,当我选中第一个复选框(我有 15 个带有复选框的候选名称)时,第 10 个复选框会自动检查自身,这也发生在第二个和第二个复选框中.十一、三、三12 等(副诗也是如此).这里我提供我的适配器类和列表项 xml.

I know that this question is already asked by other members and solution is also given by some members but the thing is that i didnt find any solution which is suitable for my app. I am creating a app in which i have a screen which will display the dynamic listview with list items a checkbox and three textviews(one is for candidate name and other two are for clockIn and clockOut time which will display after picking the date and time by date time picker).Now my problem is that when i check the first checkbox(i have 15 candidate name with checkboxs) automatically 10th checkbox checks itself and this also happens with 2nd & 11th,3rd & 12th and so on(vice verse is also true).here i am providing my adapter class and list item xml.

import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.Toast;

import com.android.feedback.ListViewCheckBox;

public class DemoAdapter extends ArrayAdapter<String>{

    private final List<String> list;
    private final Activity context;
    LayoutInflater inflater;
    TextView CItv,COtv;
    static ViewHolder holder;
    View view;

    public DemoAdapter(Activity context, List<String> list) {
        super(context, R.layout.test_listitems,list);
        // TODO Auto-generated constructor stub

        this.context = context;
        this.list = list;
    }

    static class ViewHolder {
        protected TextView text,CItv,COtv;
        protected CheckBox checkbox;
    }


    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
          view = null;
        //  final ArrayList<Integer> checkedItems = new ArrayList<Integer>(); 
        if (convertView == null) {

            inflater = context.getLayoutInflater();
            view = inflater.inflate(R.layout.test_listitems, null);
            final ViewHolder viewHolder = new ViewHolder();
            viewHolder.CItv = (TextView)view.findViewById(R.id.CITextView);
            viewHolder.COtv = (TextView)view.findViewById(R.id.COTextView);
            viewHolder.text = (TextView) view.findViewById(R.id.empTextView);
            viewHolder.checkbox = (CheckBox) view.findViewById(R.id.empCheckBox);

            viewHolder.checkbox
                    .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                        @Override
                        public void onCheckedChanged(CompoundButton buttonView,
                                boolean isChecked) {


                            if(isChecked){  
                                Object o = getItemId(position+1);
                                String keyword = o.toString();
                                Toast.makeText(getContext(), "You selected: " + keyword, 2000).show();

                            Toast.makeText(getContext(),ListViewCheckBox.DT_selected, 2000).show();
                                //  holder.CItv.setText(ListViewCheckBox.DT_selected);
                                //  holder.COtv.setText(ListViewCheckBox.outDT_selected);
                                }

                            else{
                                Object o = getItemId(position+1);
                                String keyword = o.toString();
                                //Toast.makeText(getContext(), "You unselected: " + keyword, 2000).show();
                                holder.CItv.refreshDrawableState();
                                holder.COtv.refreshDrawableState();

                            }



                        }
                    });

            view.setTag(viewHolder);
            viewHolder.checkbox.setTag(list.get(position));
            viewHolder.checkbox.setId(position);
        } else {
            view = convertView;
            ((ViewHolder) view.getTag()).checkbox.setTag(list.get(position));
        }
        holder = (ViewHolder) view.getTag();
        holder.text.setText(list.get(position));



        return view;

        }

    }

和 XML.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">


    <TableLayout android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:stretchColumns="1,2,3">

    <TableRow >


     <CheckBox    android:text=" " android:id="@+id/empCheckBox"
                  style="@style/Check" android:textColor="#000000"
                  android:textSize="12dp" 
                  android:layout_weight="1"/>

     <TextView    android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:id="@+id/empTextView"
                 style="@style/CICOTextView"
                 android:layout_weight="2"/>

    <TextView    android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:id="@+id/CITextView"
                 style="@style/CICOTextView"
                 android:text=""
                 android:layout_weight="3"/>    

    <TextView    android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:id="@+id/COTextView"
                 style="@style/CICOTextView"
                 android:text=""
                 android:layout_weight="4"/>     

    </TableRow>
    </TableLayout>
</LinearLayout>

请帮我解决这个问题.(ListViewCheckBox 是一个生成列表并将日期和时间的值存储在变量 DT_selected 和 outDT_selected 中的类).

Please help me to get rid of the problem.(ListViewCheckBox is a class which is generating list and storing the value of date and time in variables DT_selected and outDT_selected).

推荐答案

我编辑了我的答案,所以公共信息位于顶部.你会在底部找到这个问题的实际答案...

I edited my answer so the common information is located at the top. You'll find the actual answer to this question at the bottom...

这是回收的实际想法和过程,因此您可能会找出您的 getView 实现和想法有什么问题(也许其他人也会找到这个问题和答案).请参阅下面的代码示例,请忽略类型部分,因为这是附加信息.

Here's the actual idea and process of recycling so you might figure out what is wrong with your implementation and idea of getView (and maybe others too when they will find this question and answer). See further below for a code example, just ignore the type part since this is an additional information.

  • 第 1 阶段:创建用于回收的项目(convertViewnull):
    这意味着您创建了所有项目共享的布局和公共状态.如果您有监听器,您可以在此处添加它们并设计它们,以便它们可以在稍后对位置更改(当它被重用时)做出反应.因此,例如通过将位置设置为相应视图上的标签,以便侦听器可以捕获此信息并知道它当前正在操作哪个项目.您不能使用视图来存储数据.因此,当侦听器更改列表项的状态时,您应该保留此数据(在数据数组、SQLite 数据库等中)并在 阶段 2 中使用它.

  • Phase 1: Item creation for recycling (convertView is null):
    This means that you create the layout and the common state which is shared by all items. If you have listeners you have add them here and design them that way that they can react on position changes (when it is reused) later on. So for example by setting the position as tag on the corresponding view so the listener can catch this information and know on which item it is currently operating. You can't use the views to store data. So when the listener change a state on a list item you should persist this data (in an data array, in a SQLite database, etc) and use it in phase 2.

阶段 2:为给定位置设置项目状态:
您设置项目的视觉状态.一个项目可能单独更改的所有内容(文本、复选框状态、颜色等)都必须在此处设置.不仅是当前项目发生了什么变化,而且可能已被另一个项目更改.通过这种方式,您可以确保视图不会在 无效 状态下使用,因为它之前被另一个列表项重用.

Phase 2: Setup item state for given position:
You set the visual state for the item. Everything which might change individually for an item (text, checkbox state, colors, etc) has to be set here. Not only what have changed for the current item but could have been changed by another item. This way you make sure that the view is not used in an invalid state because it's being reused from another list item before.

已接受的答案已删除/编辑,但建议实施 getItemViewTypegetViewTypeCount,因此每个列表项都有自己的视图类型.编辑后的答案现在展示了如何按照此处描述的方式解决问题.

The accpeted answer was deleted / edited but was suggesting to implement getItemViewType and getViewTypeCount so every list item had its own view type. The edited answer shows now how to solve the problem the way it's described here.

重新实现 getItemViewTypegetViewTypeCount 有效,但您显然误解了它的使用(在下面进一步比较我的示例和/或 这个答案).

Reimplementing getItemViewType and getViewTypeCount works but your obviously misinterpreting it's use (compare my example further below and/or this answer).

这两种方法是为了使用两个(或更多)彼此完全不同的列表项(例如一个公共列表项和一个仅包含标题的分隔符),而不是避免回收可以重用的视图.

These two methods are there for using two (or more) list items which completely differs from each other (e.g. a common list item and a separator which contains a title only) and not to avoid recycling of a view which could be reused.

如果您无论如何都使用它们来解决您的问题,那么您可能没有理解我之前解释的过程.所以例如你有 1000 个项目并且你做了视图类型hack然后你正在创建 1000 个视图(层次结构)而不是 10 个可以轻松重用的视图.如果您只有 20 个左右的项目,那应该没有那么重要,但是如果您将这种技术用于大列表,您只是在浪费(宝贵的)内存!

If you're using them anyway to solve your problem you probably didn't understand the process I explained before. So e.g. you have 1000 items and you do the view type hack then you're creating 1000 views (hierarchies) instead probably 10 which could be reused easily. That shouldn't matter that much if you have only 20 items or so but if you use that technique for big lists you're just wasting (precious) memory!

这是一个例子:

void getItemViewType(int position) {
    return isItemAtPositionSeperator(position) ? 1 : /* normal item */ 0;
}

void int getViewTypeCount() {
    return 2; // normal item and separator
}

void View getView(int position, View convertView, ViewGroup parent) {
    int type = getItemViewType(position);

    // phase 1: see my explanation 
    if (convertView == null) {
        if (type == 0) {
            // setup your common item view - inflate it and set to convertView
        } else {
            // setup separator view - inflate it and set to convertView
        }
    }

    // phase 2: see my explanation 
    if (type == 0) {
        // set the state of the common item view based on the position
        // rely on the fact that convertView contains the view hierarchy
        // you created in convertView == null && type == 0
    } else {
        // set state of the separator based on the position
        // rely on the fact that convertView contains the view hierarchy
        // you created in convertView == null && type != 0 (else part)
    }

    return convertView;
}

<小时>

问题的实际答案...

我知道问题是什么,但现在想不出一个优雅的解决方案......

I know what the problem is but can't think of an elegant solution right now...

您的问题是您在创建视图时使用 viewHolder.checkbox.setOnCheckedChangeListener 设置了一次点击侦听器.因此,当您滚动时,它会被回收/重新用于项目,并且单击行为适用于错误的列表项目.

Your problem is that you set the click listener once with viewHolder.checkbox.setOnCheckedChangeListener when the view is created. So it is recycled / reused for items when you scroll and the click behavior applies to the wrong list item.

尽量不要使用外部的最终位置对位置进行硬编码.尝试在 return 之前设置 viewHolder.checkbox.setTag(position) 然后使用 (Integer) buttonView.getTag() 代替 position+1.所以你的回收视图将保持实际位置.

Try not to hard-code the position by using the outer final position. Try setting viewHolder.checkbox.setTag(position) before return and then use (Integer) buttonView.getTag() instead position+1. So your recycled view will keep the actual position.

当您单击复选框时,您应该将状态保留在其他地方.不要依赖 UI 状态(因为它会被回收).所以在return之前调用viewHolder.checkbox.setChecked(persistedState).

When you click a checkbox you should persists the state somewhere else. Don't rely on the UI state for that (because it will be recycled). So call viewHolder.checkbox.setChecked(persistedState) before return.

我希望这是有道理的,你明白了……;-)

I hope this makes sense and you get the idea... ;-)

这篇关于通过列表视图检查动态生成的复选框时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆