2010-09-07 45 views
7

我有一個ListView,並且在每個列表項中我有一些TextViews和一個CheckBox。當我檢查一個複選框並且我的onCheckedChangeListener觸發時,一切都按照它應該的那樣工作。但是,一旦檢查了其他隨機複選框就會被檢查。這是一個例子。Android:與ListViews和CheckBoxes問題

如果我點擊第一個CheckBox: 8被選中。 15被選中。 21被選中。 27被選中。 33被選中。 41被選中。 然後,如果我一直向上滾動,則不會檢查直到6.接下來是13.

基本上...發生了什麼事情?

回答

10

看來您正在重新使用在您實施的getView()方法上傳遞的convertView

Android將嘗試在ListView中爲不同的項目使用相同的視圖。您將需要(1)手動取消選中/檢查返回項目內的複選框(在返回getView之前總是調用setChecked或(2)不使用convertView,而是從getView返回一個新視圖

(1)建議,我認爲

+0

好吧,所以我選擇了一個。在我使用getView返回視圖之前,我做了「checkBox.setChecked(false);」。但是,現在,當我檢查複選框時,向下滾動並向上滾動,不再檢查。我知道問題出在我的實施上,而不是你的概念。我究竟做錯了什麼? – 2010-09-07 03:26:39

+0

當用戶選中複選框時,您需要存儲該項目的複選框已被選中,在代碼中的某處。例如,如果您的ListView中有40個項目,則可以使用布爾數組來存儲是否選中第i個複選框。然後在'getView'上做checkBox.setChecked(booleanArray [position])。 – yuku 2010-09-07 03:56:33

+0

也許是因爲它太晚了,但我不知道如何實際記錄位置。在getView方法中,我可以擁有該位置,但在需要實際存儲位置的OnClick中,我無法再訪問它。 – 2010-09-07 04:11:33

5

工作正常,我

public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { 

     final ViewHolder holder; 
     final Season season = (Season) getGroup(groupPosition); 
     if (convertView == null) { 
      LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      convertView = vi.inflate(R.layout.season, parent, false); 
      holder = new ViewHolder(); 
      holder.title = (TextView) convertView.findViewById(R.id.season_title); 
      holder.checkBox = (CheckBox) convertView.findViewById(R.id.season_check_box); 
      convertView.setTag(holder); 
     } else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     holder.title.setText(season.getTitle()); 
     holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 
      @Override 
      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
       season.setChecked(isChecked); 
       adapter.notifyDataSetChanged(); 
      } 
     }); 

     holder.checkBox.setChecked(season.isChecked()); // position is important! Must be before return statement! 
     return convertView; 
    } 

    protected class ViewHolder { 
     protected TextView title; 
     protected CheckBox checkBox; 
    } 
+0

我不知道什麼季節,但對我來說這似乎是工作。對於其他有問題的人(我個人對複選框沒有問題,但刪除線效果隨機出現在項目上)。所以:最終的ViewHolder持有者;而setOnCheckedChangeListener是使事情奏效的兩件事情。希望這可以幫助別人!謝謝Georgy! – erdomester 2012-04-22 18:43:53

+0

你真棒yarr ..我做了很多研發D.This是最好的解決方案 – 2015-10-19 10:56:10

+0

@Georgy Gobozov請參閱此問題以及https://stackoverflow.com/questions/44561788/checkbox-checked-unchecked-state-changes -on-滾動列表視圖,baseadapter# – 2017-06-18 14:05:13

0

我也面臨着問題,類似的國王,所以大量的閱讀後,我解決了這個問題是這樣的:

@Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     ViewHolder holder = null; 
     if (convertView == null) { 
      convertView = mInflater.inflate(R.layout.listview, null); 
      holder = new ViewHolder(); 
      holder.nameView = (TextView)convertView.findViewById(R.id.textView1); 
      holder.numberView = (TextView)convertView.findViewById(R.id.textView2); 
      holder.cb = (CheckBox)convertView.findViewById(R.id.checkBox1); 
      convertView.setTag(holder);     
     } else { 
      holder = (ViewHolder)convertView.getTag(); 
     } 
     holder.nameView.setText(mData.get(position).toString()); 
     holder.numberView.setText(mNumber.get(position).toString()); 
     holder.cb.setChecked(false); 
     holder.cb.setTag(position); 



     if(selected.indexOf(mNumber.get(position).toString()) >= 0) // Check whether this row checkbox was checked, for that we previously stored the textview text in selected variable 
     { 

     holder.cb.setChecked(true); 
     } 

     return convertView; 
    } 

} 

在這裏,我正在做的getView()我沒有選中所有的複選框,並再次手動檢查我需要根據它對應的文本檢查檢查。因此,如果用戶在檢查第一個複選框後向下滾動,則視圖中的所有複選框都將被取消選中,如果他再次滾動,則所有複選框都將被取消選中,但之前單擊的複選框將被再次複查。

0

該問題可以通過保持CheckBox狀態輕鬆解決。自定義和解釋的完整的樣例類代碼相同的是below_

public class AreaDataAdapter extends ArrayAdapter<String> { 
    private List<String> areaList; 
    private Activity context; 
    ArrayList<Boolean> positionArray; 

    public AreaDataAdapter(Context context, int textViewResourceId, 
      List<String> offersAreaList) { 
     super(context, textViewResourceId, offersAreaList); 
     // TODO Auto-generated constructor stub 
     this.context=context; 
     this.areaList = offersAreaList; 

     positionArray = new ArrayList<Boolean>(offersAreaList.size()); 
      for(int i =0;i<offersAreaList.size();i++){ 
       positionArray.add(false); 
      } 

    } 

    public AreaDataAdapter(Activity context, List<String> offersAreaList) { 
     super(ShowOffersActivity.this, R.layout.filterlist_row, offersAreaList); 
     this.context=context; 
     this.areaList=offersAreaList; 

     positionArray = new ArrayList<Boolean>(offersAreaList.size()); 
      for(int i =0;i<offersAreaList.size();i++){ 
       positionArray.add(false); 
      } 

    } 

    public View getView(final int position, View convertView,ViewGroup parent) { 
     View row=convertView; 
     FilterViewHolder holder; 
     if (row==null) { 
      LayoutInflater inflater=getLayoutInflater(); 

      row=inflater.inflate(R.layout.filterlist_row, parent, false); 
      holder = new FilterViewHolder(); 
      holder.filterCheckBox = (CheckBox)row.findViewById(R.id.filter_checkbox); 
      holder.filterCheckBox.setTypeface(fontFace); 

      row.setTag(holder); 
     } else { 
      //holder = (View) row; 
      holder = (FilterViewHolder) row.getTag(); 

      /* When a listview recycles views , it recycles its present state as well as listeners attached to it. 
      * if the checkbox was checked and has a onCheckedChangeListener set, both will remain a part of 
      * recycled view based on position. So it is our responsibility to reset all states and remove 
      * previous listeners. 
      * The listener was removed as below:- 
      */ 
      holder.filterCheckBox.setOnCheckedChangeListener(null); 

     } 

      holder.filterCheckBox.setText(areaList.get(position)); 
      holder.filterCheckBox.setFocusable(false); 
      holder.filterCheckBox.setChecked(positionArray.get(position)); 
      holder.filterCheckBox.setText(areaList.get(position)); 

      holder.filterCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() { 

       @Override 
       public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
        // TODO Auto-generated method stub 
        if (isChecked) { 
         //change state of concern item in 'positionArray' array to 'True' 
         positionArray.set(position, true); 
         //add the checked item in to area list which used to filter offers. 
         filterOffersByThisAreaList.add(areaList.get(position)); 

        } else { 
         //change state of concern item in 'positionArray' array to 'True' 
         positionArray.set(position, true); 
         //remove the unchecked item in to area list which used to filter offers. 
         filterOffersByThisAreaList.remove(areaList.get(position)); 

        } 
       } 
      }); 
     return row; 
    } 

} 

定製行(filterlist_row)ListView含有這些CheckBox s是作爲below_

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:orientation="vertical" > 

<CheckBox 
    android:id="@+id/filter_checkbox" 
    style="@style/CodeFont" 
    android:button="@drawable/bg_custom_checkbox" 
    android:text="Indian" /> 

<View 
    android:layout_width="match_parent" 
    android:layout_height="1dp" 
    android:background="#c9c9c3" /> 

</LinearLayout> 

定製CheckBox backgroung是below_

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
<item android:drawable="@drawable/checkbox_s" android:state_checked="true"></item> 
<item android:drawable="@drawable/checkbox_ns" android:state_checked="false"></item> 

</selector> 
0

我的交換機視圖有同樣的問題。經過大量的搜索和閱讀後,我發現這個問題是由Android推動的視圖優化的結果。它試圖重用視圖對象。所以,基本上,當你點擊一個開關或複選框時,你也會在另一個視圖中觸發更改的回調。優化確實有效,但如果你不注意,或者只是不知道行爲(像我一樣),會發生一些非常奇怪的結果。

不管怎麼說,我覺得這是簡單的解決方案:

最好的做法是重用convertView的getView()方法傳遞。這樣你可以優化listview使用的Ram的數量。因此,我將視圖存儲在ViewHolder中,並編寫了onCheckedChanged事件。訣竅是,在設置之前,如果開關被選中或沒有(在你的情況下,檢查複選框)並定義CheckedChange偵聽器,我只需用空值重置回調,這可以確保不會觸發另一個開關的事件。

這裏是片段:

... 
viewHolder.switchView.setOnCheckedChangeListener(null); 
viewHolder.switchView.setChecked(myObject.getStatus() > 0); 
... 
viewHolder.switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 
      @Override 
      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
       ... 
      } 
     }); 

myObject的是具有存儲在光標數據的最終目的。

不管開關是否被檢查,你都必須調用setChecked方法。

希望它可以幫助別人!

0
@Override 
public int getViewTypeCount() { 
    return getCount(); 
} 

@Override 
public int getItemViewType(int position) { 
    return position; 
} 

@Override 
public int getCount() { 
    return names.length; 
} 

@Override 
public long getItemId(int position) { 
    return 0; 
} 

將此方法添加到自定義適配器中。它爲我工作