Android如何知道哪个复选框被选中

7

我正在制作我的第一个Android应用程序,但我遇到了一个问题,在谷歌上找不到答案。

我想要一个带有复选框的项目列表。我希望这两个元素都可以被点击。

    public class MyItem extends ListActivity {
        private ArrayList<MyItem> items;
        public void onCreate(Bundle savedInstanceState) {
            /* code which creates instances of MyItem and inserts them on the *list* variable */
        MyArrayAdapter adapter = new MyArrayAdapter(this, R.layout.my_item, list);

        setListAdapater(adapter);
        setContentView(R.layout.items_list);
    }
        public onListItemClick(ListView l, View v, int position, long id){
            //handles the click on an item
        }

    public class MyArrayAdapter extends ArrayAdapter<MyItem>{
        private MyItem item;
        public MyArrayAdapter(Context context, int resourceId, ArrayList<MyItem> list){
            //code for the constructor
        }
        public getView(int position, View convertView, ViewGroup parent){
            convertView = inflater.inflate(resourceId, null);


            this.item = list.get(position);
            if (this.item == null) {
                return convertView;
            }
            else{
                if (resourceId == R.layout.my_item) {
                    final CheckBox cb = (CheckBox)convertView.findViewById(R.id.checkbox);

                    if(cb != null){
                        //initially
                        if(chosen)
                            cb.setChecked(true);
                        else
                            cb.setChecked(false);
                        //set listener
                        cb.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View arg0) {
                                if(cb.isChecked())
                                    chosen = true;
                                else
                                    chosen = false;
                            }
                        });
                    }
                }
            return convertView;
        }
    }    
}

不要担心所选的变量,我只是为了简化代码而这样写。实际上它对应数据库中的一个值。单击项目可以正常工作。但是,当我单击复选框时,会发生以下情况:
  • 我单击的复选框看起来被选中了(这是 Android UI 的工作)
  • 内部被选中的复选框是屏幕上最后一个,也就是说,如果我的屏幕显示了 8 个项目,而我在其中一个上单击(无论是哪一个),则检查出现在正确的复选框中,但在内部,第 8 个项目正在被选中。
我将不胜感激你提供的任何帮助。提前致谢。
4个回答

6
实际上,支持chosen的实现是关键。Android在列表视图中进行了一些优化,以允许您重用列表项视图,以避免过多对象创建和垃圾回收(这通常会导致滑动不流畅)。因此,您必须确保在相关时,您知道您正在处理哪个列表项。
假设您有100个列表项。您的屏幕可能无法显示所有条目。您可能只显示十个项目。因此,为了显示这些可见项目,将创建10个视图(实际上是视图层次结构)。当您向下滚动到下一个十个项目时,列表可能只会创建一个新视图(总共11个项目在屏幕上可见,其中半个项目在屏幕顶部,半个项目在屏幕底部),其余项目重用之前创建的视图。
因此,表示第一个屏幕的概念表可能如下所示:
项目 视图 ------- -------- 项目1 视图1 项目2 视图2 项目3 视图3 项目4 视图4 项目5 视图5 项目6 视图6 项目7 视图7 项目8 视图8 项目9 视图9 项目10 视图10
向下滚动十个项目后,它可能看起来像这样(可能不完全相同,但可以让您了解):
项目 视图 ------- -------- 项目11 视图1 项目12 视图2 项目13 视图3 项目14 视图4 项目15 视图5 项目16 视图6 项目17 视图7 项目18 视图8 项目19 视图9 项目20 视图10
因此,您可以从中得出一个结论,即单个给定视图可以表示不同的项目,因此您的事件处理程序必须在找到相关项时更加灵活。
所有这些都是为了让您有一些背景,以便您可以更改您实现的getView方法。这里是您实际遇到的问题:变量item在Adapter的范围内。不幸的是,我猜测您没有发布并且用chosen替换的代码使用了item。每当创建一个项视图时,您都会设置item。这意味着在创建了那前8个视图之后,item被设置为列表中的第8个项。每当您点击复选框时,您都在使用item,该项是第8个项而不是对应于您单击的列表项视图的项。

以下是我推荐的getView结构:

public getView(int position, View convertView, ViewGroup parent){
        View view = convertView;
        if (view == null) {
            view = inflater.inflate(R.layout.my_item, null);
        }

        final MyItem item = list.get(position);
        final CheckBox cb = (CheckBox)convertView.findViewById(R.id.checkbox);
        // This stores a reference to the actual item in the checkbox
        cb.setTag(item);

        if(item.chosen)
            cb.setChecked(true);
        else
            cb.setChecked(false);

        //set listener
        cb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // This gets the correct item to work with.
                final MyItem clickedItem = (MyItem) view.getTag();
                if(cb.isChecked())
                    clickedItem.chosen = true;
                else
                    clickedItem.chosen = false;
            }
        });

        return view;
    }
}

请注意,我已经取消了类级别的item变量。

它的运行非常完美,除了一个细节。setTag/getTag必须针对复选框而不是视图进行操作。谢谢,非常感谢:D - Inês
1
已更新以修复你指出的错误,以防其他人遇到这段代码。 - kabuko

2

试试这个

public getView(int position, View convertView, ViewGroup parent){
    View view = convertView;
    if (view == null) {
        view = inflater.inflate(R.layout.my_item, null);
    }

    final MyItem item = list.get(position);
    // This stores a reference to the actual item in the view
    view.setTag(item);

    final CheckBox cb = (CheckBox)convertView.findViewById(R.id.checkbox);

    //set listener
    cb.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            // This gets the correct item to work with.
            final MyItem clickedItem = (MyItem) view.getTag();
            if(cb.isChecked())
                clickedItem.chosen = true;
            else
                clickedItem.chosen = false;
        }
    });


    cb.setChecked(item.chosen);
    return view;
}

为什么不使用 clickedItem.chosen = cb.isChecked()? - cyroxis

0

你应该将isChecked值保存在MyItem对象中,在你的adapter的getView方法中显式地将其设置为checkbox。使用onCheckedChangedListener。


我这么做。我使用OnClickListener,因为我尝试了OnCheckedChangeListener,但它不起作用,所以我尝试了onClick。结果是一样的。我的问题不是保存更改(它将更改保存到列表上的第8项)。我的问题是它说我点击了第8个,而实际上我点击了第1个或其他什么东西。 - Inês

0

如果我理解你的解释正确,那么你有一个列表,列表中的每一行都有一个复选框和一个文本视图。在我的应用程序中,我有类似的东西,但不是尝试让复选框和文本视图都可点击并对其做出反应,而是使用ListView的onItemClick。当您捕获到用户按下列表中的项目时,然后在代码中可以检查或取消选择复选框。它给用户视觉上的印象,使他们能够勾选复选框,但实现起来非常容易。


我不太理解你的回答,但是@kabuko的回答解决了问题。无论如何,谢谢 :) - Inês

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接