1

我有一个 ExpandableListView。每个孩子都有一个 CheckBox 和一个 TextView。当用户点击子行时,CheckBox 应该改变其状态(选中与未选中)。如果用户直接点击复选框,这将正常工作。但是,如果用户点击文本视图(同一行,紧邻复选框的右侧),我会在尝试引用复选框时立即收到空指针错误。任何人都可以看到有什么问题吗?

编辑:阅读下面的建议后,我做了一些调查,并意识到我可以在 getChildView() 下的适配器内实现我的 clickListener。这解决了我的空指针问题,因为我可以轻松获得对子视图的引用。

但是,它产生了另一个我认为没有优雅解决方案的问题。每次单击孩子时,我都需要更改列表视图本身。此列表的数据位于 ArrayList 中,其范围在 Activity 内(而不是在 Adapter 中)。如果我的 clickListener 在 Adapter 中,如何回调 Activity 以更改 ArrayList?

这让我觉得是第 22 条规则。如果我希望能够操作我的数据,我无法获得对子视图的引用。但是如果我想引用我的子视图,我的数据超出了范围,所以我无法操作它。人们如何解决这个问题?我肯定错过了什么。

我将输入相关的适配器代码,您可以在其中看到我尝试添加子 onClickListener 的开始。

再次感谢!

    public class Settings extends Activity {

        //this is the list I need to access from the adapter if my click listener is there
        private ArrayList<Categories> categoriesList = null;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_smart_settings);

            db = new EventsDB(this);

            expListGroups = new ArrayList<ExpandListGroup>();
            setGroups();

            /* Set up the data adapter */
            expAdapter = new ExpandListAdapter(Settings.this, expListGroups);

            populateExpandableGroups();

        }

        public void setGroups() {

            /* Create lists of the individual line items */
            categoriesList = db.getCategoriesForClient(client);
            locationsList = db.getLocationsForClient(client);

            /* Add an item to the locations list to allow the user to add a new location */
            locationsList.add(new ClientSmartFinderLocations(client, "Add Location", null, false));

            ExpandListGroup categoryGroup = new ExpandListCategory("Choose Categories", categoriesList);
            ExpandListGroup locationGroup = new ExpandListLocation("Choose Locations", locationsList);

            expListGroups.add(categoryGroup);
            expListGroups.add(locationGroup);

        }

        private void populateExpandableGroups() {
            expandableList = (ExpandableListView) findViewById(R.id.expandable_list);
            expandableList.setAdapter(expAdapter);

            //I've removed this section and moved it to the adapter, per my edit above
//            expandableList.setOnChildClickListener(new OnChildClickListener() {
//            
//                @Override
//                public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
//                  
//                  /* Update the finder setting for this client */
//                  String category = categoriesList.get(childPosition).getCategory();
//                  Boolean isSelected = !categoriesList.get(childPosition).getIsSelected();
//                  db.setClientCategory(client, category, isSelected);
//          
//                  /* Update the check box to provide feedback to the user */
//                  View view = parent.getChildAt(childPosition - parent.getFirstVisiblePosition() + 1);
//                  CheckBox checkBox = (CheckBox) view.findViewById(R.id.check_box);
//
//                        //error occurs here
//                  checkBox.setChecked(!checkBox.isChecked());
//                            return true;
//                }
//            });

            expAdapter.notifyDataSetChanged();
        }




public class ExpandListAdapter extends BaseExpandableListAdapter {

    //other methods

    @Override
    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, final ViewGroup parent) {


            view = getCategoryChildView(groupPosition, childPosition, view);

            view.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {

                    TextView tv = (TextView) v.findViewById(R.id.expand_list_item);
                    CheckBox checkBox = (CheckBox) v.findViewById(R.id.check_box);

                    String category = tv.getText().toString();
                    Boolean isSelected = !checkBox.isSelected();

                    db = new EventsDB(context);
                    db.setClientCategory(client, category, isSelected);

                    checkBox.setChecked(!checkBox.isChecked());

                    //here I need to do some things that require me to manipulate the categoriesList from the Activity class - but it is out of scope
                }
            });

        return view;
    }
}

<CheckBox
    android:id="@+id/check_box"
    android:layout_marginLeft="30dp"
    android:focusable="false"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/expand_list_item"
    android:paddingLeft="10dp"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="@dimen/smart_finder_settings_font_size"
    android:textColor="#FFFFFF" />

4

4 回答 4

1

我认为我有一个解决方案。如果我在 Adapter 中创建 Settings 活动类的实例,我可以将常用的 getter/setter 方法添加到 Settings 类。然后我可以从适配器调用这些方法以获取该列表,对其进行修改,然后将其推回设置类,一切都应该很好。

这是一种基本的 OOP 方法,但对我来说,最困难的是实例化活动的想法。我不知道这是否常见,但对我来说似乎很奇怪。有人有更优雅的解决方案吗?

在设置类中:

public ArrayList<Categories> getCategoriesList() {
    return categoriesList;
}

public void setCategoriesList(ArrayList<Categories> list) {
    categoriesList = list;
}

在适配器内:

Settings settings = new Settings();
ArrayList<Categories> tempCategoriesList = new ArrayList<Categories>();
tempCategoriesList = settings.getCategoriesList();
//make changes to the list
settings.setCategoriesList(tempCategoriesList);
于 2013-06-14T06:01:11.647 回答
0

user55410 在正确的轨道上。在您的 Settings() Activity 中,将 categoryList 设为静态,然后当您使用在您的新实例中创建的 getter/setter 方法对其进行更改时,它将修改 Settings.categoryList 的所有实例。

于 2014-02-10T00:24:12.307 回答
0

我不是专业人士,所以请记住这一点。但是如何存储需要 clicklistener 在 gobal 应用程序类中操作的数据呢?也许不是最优雅的,但可能会奏效。

于 2013-12-31T22:13:36.930 回答
0

您应该在您的内部设置复选框选中状态,ExpandListAdapter而不是直接访问内部的视图ExpandableListView

于 2013-06-12T23:22:34.393 回答