使用ListView“打一个复选框”游戏

时间:2010-09-01 20:43:22

标签: android listview checkbox cursor listactivity

我有一个最初使用ArrayAdapter的ListActivity。我的ListView中的每个项目都包含一个复选框。

我将Adapters更改为CursorAdapter。一切都工作正常,除了复选框失控。例如:当我单击位置1中的复选框时,将检查位置4中的复选框。如果我再次单击位置1中的复选框,它将检查(即:当我单击位置1中的复选框时,如果未选中位置4中的复选框,则将检查位置4中的复选框;否则,复选框位置检查1)。取消选中复选框似乎没有显示任何奇怪的行为。有什么想法吗?

更新:根据屏幕上显示的项目向后检查复选框。我的意思是,如果有5个项目可见,点击第1个将检查第5个,点击第2个,检查第4个,点击第3个将检查第3个。此外,一旦检查了一个,它们都开始正常运行。

显然评论这会让问题消失:

    if (holder.chkSelect != null) {
        holder.chkSelect.setOnCheckedChangeListener(this);
    }

这肯定与showMultiPanel弹出有关,可能会减少可以看到的行数。虽然我不明白为什么它适用于ArrayAdapter。

这是我的CursorAdapter的副本

public class InboxAdapter extends CursorAdapter implements CheckBox.OnCheckedChangeListener {
    private int mCheckedCount = 0;

    public InboxAdapter(Context context, Cursor c) {
        super(context, c);
    }

    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (buttonView.getId() == R.id.inbox_itemcheck) {
            if (isChecked) {
                mCheckedCount++;
            }
            else {
                mCheckedCount--;
            }
            ActivityInbox.this.showMultiPanel((mCheckedCount > 0) ? true : false);
        }
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        InboxHolder holder = (InboxHolder)view.getTag();

        if (holder.txtDate != null) {
            DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
            Date d = new Date(cursor.getInt(cursor.getColumnIndex("created_on")) * 1000L);
            holder.txtDate.setText(df.format(d));
        }
        if (holder.txtSubject != null) {
            holder.txtSubject.setText(cursor.getString(cursor.getColumnIndex("subject")));
            if (cursor.getInt(cursor.getColumnIndex("read")) == 0) {
                holder.txtSubject.setTypeface(null, Typeface.BOLD);
            }
            else {
                holder.txtSubject.setTypeface(null, Typeface.NORMAL);
            }
        }

        if(holder.txtSummary != null) {
            holder.txtSummary.setText(cursor.getString(cursor.getColumnIndex("summary")));
        }

        if (cursor.getInt(cursor.getColumnIndex("read")) == 0) {
            view.setBackgroundResource(R.drawable.selector_inbox_unread);
        }
        else {
            view.setBackgroundResource(R.drawable.selector_inbox_read);
        }

        if (holder.lMessageType != null) {
            if (cursor.getInt(cursor.getColumnIndex("read")) == 0) {
                holder.lMessageType.setVisibility(View.VISIBLE);
            }
            else {
                holder.lMessageType.setVisibility(View.INVISIBLE);
            }
        }
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        LayoutInflater inflater = LayoutInflater.from(context);
        View v = inflater.inflate(R.layout.layout_inbox_item, parent, false);

        InboxHolder holder = new InboxHolder();
        holder.txtDate = (TextView) v.findViewById(R.id.inbox_item_date);
        holder.txtSubject = (TextView) v.findViewById(R.id.inbox_item_subject);
        holder.txtSummary = (TextView) v.findViewById(R.id.inbox_item_summary);
        holder.chkSelect = (CheckBox) v.findViewById(R.id.inbox_itemcheck);
        holder.lMessageType = (LinearLayout) v.findViewById(R.id.inbox_messagetype);

        v.setTag(holder);

        if (holder.chkSelect != null) {
            holder.chkSelect.setOnCheckedChangeListener(this);
        }
        return v;
    }

}

1 个答案:

答案 0 :(得分:0)

请注意,ListView可以为表的多行重用单个View,并由适配器决定是否发生这种情况。我相信CursorAdapter设置为尽可能通过池化视图实例并仅创建足以构建屏幕的方式来执行此操作。

对于简短列表的简单解决方案,只需坚持使用ArrayAdapter,并提前读取所有数据。这避免了整个问题。

如果您想坚持使用CursorAdapter,您需要自己存储已检查的状态。一种方法是保留被检查的HashSet个id。在复选框中单击侦听器,通过在集合中添加或删除该行的ID来更新它。在bindView中,根据行的ID是否在地图中设置复选框状态。您可能还希望在bindView中设置侦听器,您可以在其中将final局部变量设置为id,并且可以在侦听器的代码中使用该值。