2012-09-28 41 views
8

自定義適配器我有使用自定義適配器如圖所示一個ListView:列表視圖包含的CheckBox

private class CBAdapter extends BaseAdapter implements OnCheckedChangeListener{ 

    Context context; 
    public String[] englishNames; 
    LayoutInflater inflater; 
    CheckBox[] checkBoxArray; 
    LinearLayout[] viewArray; 
    private boolean[] checked; 

    public CBAdapter(Context con, String[] engNames){ 
     context=con; 
     englishNames=engNames; 
     inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     checked= new boolean[englishNames.length]; 
     for(int i=0; i<checked.length; i++){ 
      checked[i]=false; 
      //Toast.makeText(con, checked.toString(),Toast.LENGTH_SHORT).show(); 
     } 
     checkBoxArray = new CheckBox[checked.length]; 
     viewArray = new LinearLayout[checked.length]; 
    } 

    public int getCount() { 
     return englishNames.length; 
    } 

    public Object getItem(int position) { 
     // TODO Auto-generated method stub 
     return null; 
    } 

    public long getItemId(int position) { 
     // TODO Auto-generated method stub 
     return 0; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 

     if(viewArray[position] == null){ 

      viewArray[position]=(LinearLayout)inflater.inflate(R.layout.record_view_start,null); 

      TextView tv=(TextView)viewArray[position].findViewById(R.id.engName); 
      tv.setText(englishNames[position]); 

      checkBoxArray[position]=(CheckBox)viewArray[position].findViewById(R.id.checkBox1); 
     } 

     checkBoxArray[position].setChecked(checked[position]); 
     checkBoxArray[position].setOnCheckedChangeListener(this); 
     return viewArray[position]; 
    } 


    public void checkAll(boolean areChecked){ 
     for(int i=0; i<checked.length; i++){ 
      checked[i]=areChecked; 
      if(checkBoxArray[i] != null) 
       checkBoxArray[i].setChecked(areChecked); 
     } 
     notifyDataSetChanged(); 
    } 

    public void onCheckedChanged(CompoundButton cb, boolean isChecked) { 
     for(int i=0; i<checked.length; i++){ 
      if(cb == checkBoxArray[i]) 
       checked[i]=isChecked; 
     } 




    } 
    public boolean itemIsChecked(int i){ 
     return checked[i]; 
    } 

} 

的佈局是相當簡單的所以除非有人認爲它們是相關的,我不會張貼。

問題是,某些CheckBox沒有響應。它似乎是佈局第一次顯示時可見的那些。任何你必須向下滾動才能按預期工作。

任何指針讚賞。

回答

15

您從答案中得到的代碼有效,但效率很低(您可以實際看到這一點,只需滾動ListView並檢查Logcat即可看到垃圾回收器正在工作)。一種改進getView方法,將回收的觀點是下面這樣:

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    LinearLayout view = (LinearLayout) convertView; 
    if (view == null) { 
      view = (LinearLayout) inflater.inflate(R.layout.record_view_start, parent, false); 
    } 
    TextView tv = (TextView) view.findViewById(R.id.engName); 
    tv.setText(getItem(position)); 
    CheckBox cBox = (CheckBox) view.findViewById(R.id.checkBox1); 
    cBox.setTag(Integer.valueOf(position)); // set the tag so we can identify the correct row in the listener 
    cBox.setChecked(mChecked[position]); // set the status as we stored it   
    cBox.setOnCheckedChangeListener(mListener); // set the listener  
    return view; 
} 

OnCheckedChangeListener mListener = new OnCheckedChangeListener() { 

    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
     mChecked[(Integer)buttonView.getTag()] = isChecked; // get the tag so we know the row and store the status 
    } 
}; 

關於你的代碼從你的問題,起初我以爲這是因爲你的方式設置的行是錯誤的,但我不明白爲什麼當您從列表中分離行視圖時,適配器將具有該行爲。此外,我甚至測試了代碼,它在CheckBoxes(但內存處理很差)方面效果很好。也許你正在做其他事情,使適配器無法正常工作?

+0

你如何做一個EcxpandableListView與子複選框? – RicNjesh

+0

@RicNjesh您將需要使用'getChildView()'方法,該方法在需要子行時被調用。 – Luksprog

+0

什麼是在這種情況下mchecked以及如何申報? –

1

讓我先說,你已經扔掉的使用適配器的主要優勢之一:可重複使用的意見。對每個創建的View持有一個堅實的參考文件存在觸及記憶體上限的高風險。當它非空時,您應該重用convertView,並在convertView爲空時創建視圖。有很多教程向你展示如何做到這一點。

在一個適配器中使用的視圖通常有一個OnClickListener由父母View連接,因此您可以在ListView上設置OnItemClickListener。這將取代單個視圖上的任何觸摸監聽器。嘗試使用XML在CheckBox上設置android:clickable="true"

+0

感謝有關convertView的提高。我一直在想這個參數是什麼。我想我可能有解決原始問題的方法,但我仍在測試。我會盡快發佈。 – s1ni5t3r

0

這可能不是最優雅或有效的解決方案,但它適用於我的情況。出於某種原因試圖從視圖數組中重用視圖或使用convertView會使每個事物變得搖擺不定,並且CheckBoxes無法響應。

奏效是創建一個新的視圖每次getView()的唯一的事情被調用。

public View getView(final int position, View convertView, ViewGroup parent) { 
     LinearLayout view; 
     view=(LinearLayout)inflater.inflate(R.layout.record_view_start,null); 


     TextView tv=(TextView)view.findViewById(R.id.engName); 
     tv.setText(englishNames[position]); 

     CheckBox cBox=(CheckBox)view.findViewById(R.id.checkBox1); 
     cBox.setChecked(checked[position]); 
     cBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){ 

      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
       checked[position]=isChecked; 
      } 
     }); 
     return view; 
    } 

查找該溶液中還在於,我打電話單獨定義的onCheckedChangedListener,即然後確定了由ID複選框,而不是具有用於每個複選框新的偵聽阻礙。

由於還沒有,因爲我希望其他人可能有相當浪費的重建視圖每次對於一些輸入我沒有標明這是正確的答案。

+1

關於使用帶有CheckBox的行的自定義適配器的ListView有很多問題,你應該多看看這些解決方案。你的代碼工作,但效率很低,每次滾動ListView時,你都會創建新的視圖。 – Luksprog

+0

我完全同意Luksprog,但經過多次嘗試,使用適用於其他解決方案的解決方案後,我無法找到除此之外的解決方案。希望垃圾收集能夠跟上浪費的視圖,不會造成內存問題,而且舊手機不會太慢。在我的應用程序中,在大多數情況下,listview不會有太多的條目,因此滾動應該保持在最低限度。 – s1ni5t3r

+1

您的代碼現在工作的原因是因爲您每次都膨脹行,並且避免了「OnCheckedChangeListener」混淆了「CheckBox」狀態。您絕對不應該忽略'getView'方法中的視圖回收。這裏是你改進的'getView'方法,它應該做你想做的事情,但也會回收視圖。 https://gist.github.com/3917222 – Luksprog

相關問題