2013-06-12 29 views
1

我有一个ExpandableListView。每个孩子都有一个CheckBox和一个TextView。当用户点击一个子行时,CheckBox应该改变其状态(选中或未选中)。如果用户直接点击复选框,此功能将正常工作。但是,如果用户点击文本视图(同一行,紧挨着复选框的右侧),只要尝试引用复选框,就会收到空指针错误。任何人都可以看到什么是错的?Android ExpandableListView在哪里放置onClickListener

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

但是,它造成了另一个问题,我看不到优雅的解决方案。每次点击一个孩子时,我需要对列表视图本身进行更改。此列表的数据位于范围在Activity内的ArrayList中(不在Adapter中)。如果我的clickListener在适配器中,我怎样才能回调活动来修改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" /> 

回答

0

应设置复选框选中您ExpandListAdapter内部状态而不是访问ExpandableListView里面直接的看法。

+0

谢谢。我确实在适配器内设置了复选框的初始状态。这里我正在尝试处理onChildClick事件。除了切换复选框的状态之外,在解决空指针问题之后还需要执行其他处理。你是否说我应该在适配器内部进行此操作?我会在适配器中做什么?再次感谢! – Alex

1

我认为我有一个解决方案。如果我在适配器中创建了Settings活动类的实例,我可以将常用的getter/setter方法添加到Settings类。然后,我可以从适配器调用这些方法来获取这个列表,修改它,然后将它推回到Settings类,并且一切都会好的。

这是一种基本的面向对象方法,但对我来说,心理挂断是实例化一个活动的想法。我不知道这是否常见,但对我来说似乎很奇怪。任何人都有更优雅的解决方案?

在设置类:

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); 
+0

没有。这没有奏效。看起来像当我实例化新的设置()时,我创建了一个全新的副本,我没有得到原始数据。所以,我仍然坚持。我无法获取我的数据。我完全没有想法。任何人都可以帮我吗? – Alex

0

我不是一个职业球员,所以要考虑到这一点。但是如何存储你需要的clicklistener在gobal应用程序类中操作的数据呢?也许不是最优雅的,但可能工作。

0

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