获取的问题,同时检查通过列表视图中动态生成复选框视图、复选框、动态、问题

2023-09-11 10:40:58 作者:控心少年°

我知道这个问题已经被问的其他成员和解决方案也受到一些成员发出,但事情是,我没有找到任何解决方案,这是适合我的应用程序。 我创建一个应用程序中,我有一个屏幕,显示动态列表视图与列表项的复选框和三个textviews(一个是候选人的名字和其他两个用于clockIn和CLOCKOUT时间,这将显示由采摘的日期和时间后,日期时间选择器)。现在我的问题是,当我选中第一个复选框(我有checkboxs自动第10复选框检查本身,这也正好与第二和放15个候选名); 11日,第3和放大器;第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 和想法(或者其他人太多的时候,他们会发现这个问题,并回答)。见下文为code的例子,只是忽略的类型部分,因为这是一个额外的信息。

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阶段:项目创造回收( convertView ): 这意味着您创建布局和由所有项目共享的公共状态。如果你的听众,你在这里添加它们,并设计他们的方式,他们可以在位置的变化作出反应(当它被重复使用)以后。因此,例如通过设置相应的视图中的位置标记,以便听者可以捕捉这些信息,知道哪个项目是目前经营。不能使用视图来存储数据。因此,当听者更改列表项的状态,你应该保留此数据(在数据阵列,在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.

该accpeted答案被删除/修改,但被建议落实 getItemViewType getViewTypeCount 让每一个列表项有其自己的视图类型。 编辑后的答案的显示现在如何解决问题它这里所描述的方式。

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.

重新实现 getItemViewType getViewTypeCount 的作品,但你显然misinter preting它的使用(比较进一步说明我的例子和/或this回答)。

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个项目和你的视图类型的破解的,那么你正在创建1000次(层次),而不是可能是10,它可重复使用的轻松的。这应该不是问题,如果你只有20项左右,但这么多,如果你使用的技术,你只是在浪费大名单(precious)内存!

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.

尽量不要的硬code 的使用外最后位置的位置。尝试设置 viewHolder.checkbox.setTag(位置)返回然后用(整数) buttonView.getTag(),而不是位置+ 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.

当你点击一个复选框,你应该坚持国家其他地方。不要依赖于该用户界面状态(因为它会被回收)。于是呼 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... ;-)