2013-06-12 61 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的所有實例。