开发者

Android How to know which check box is selected

I'm making my first Android application and I'm having a problem for which I can't find the answer anywhere on Google.

I want a list of items with checkboxes. I want both the item itself and the checkbox to be clickable.

    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
                                    开发者_JAVA技巧chosen = false;
                            }
                        });
                    }
                }
            return convertView;
        }
    }    
}

Don't worry about the chosen variable. I wrote that to simply the code. It actually corresponds to a value in a database. The clicking on an item works just fine. However when I click on a checkbox what happens is this:

  • the checkbox in which I clicked appears selected (this is the work of the Android's UI)
  • the checkbox that internally is checked is the last one on the screen whichever it is, i.e., if I my screen displays 8 items and I click in one of them (doesn't matter which one) the check appears in the correct checkbox but internally, the 8th item is the one getting checked.

I would appreciate any help you could provide me. Thanks in advance.


Actually, the implementation backing chosen is key. Android does some optimization with list views to allow you to reuse the list item views to avoid excessive object creation and garbage collection (which would often lead to jerky scrolling). As such, you have to make sure that whenever relevant, you know exactly which list item you're working with.

Let's say that you have a 100 list items. Your screen is probably not going to be able to display all of them. You might only show ten items at a time. So 10 views (really view hierarchies) are created to display those visible items. When you scroll down to the next ten items, instead of creating 10 new views (for a total of 20), the list might only create one more (to cover the case where half of one item is showing at the top and half of one is showing at the bottom of the screen for a total of 11 items visible on the screen) and the rest of items reuse the views created before.

So a conceptual table representing the first screen might look like this:

Item     View
-------  --------
Item 1   View 1
Item 2   View 2
Item 3   View 3
Item 4   View 4
Item 5   View 5
Item 6   View 6
Item 7   View 7
Item 8   View 8
Item 9   View 9
Item 10  View 10

And for after scrolling down ten items, it might look a little like this (probably not exactly, but this gets you the idea):

Item     View
-------  --------
Item 11  View 1
Item 12  View 2
Item 13  View 3
Item 14  View 4
Item 15  View 5
Item 16  View 6
Item 17  View 7
Item 18  View 8
Item 19  View 9
Item 20  View 10

So what you can gather from this is that a single given view can represent different items as you scroll around. This means that your event handlers have to be a little more dynamic in how they find the item they're related to.

All this is to give you a bit of background so that you can change how you're implementing your getView method. Here's your actual problem: the variable item is in the scope of your Adapter. Unfortunately, I'm guessing that your code that you haven't posted here that you've replaced with chosen uses item. You set item whenever an item view gets created. This means that after those first 8 views are created, item is set to the 8th item in your list. Whenever you click on a checkbox, you're using item which is the 8th item and not the item that corresponds to the list item view that you clicked.

Here's the structure for getView that I'd recommend:

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;
    }
}

Note that I've gotten rid of the class-level item variable.


Try this

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;
}


You should save isChecked value in your MyItem object and explicit set checked to checkbox in getView method of your adapter. Use onCheckedChangedListener.


If I am following your explanation it sounds like you have a list and each row in the list has a Checkbox and a TextView. In my app I have something similar and instead of trying to make both the Checkbox and TextView clickable and react to that I use the ListView's onItemclick. When you catch the user pressed an item in the list, then in the code you can check or un-check the Checkbox. It gives the visual impression that the user is able to check the box, but is super easy to implement.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜