2014-02-10 31 views
0

我對Android非常陌生,目前在使用自定義列表適配器時遇到了一些問題。ListAdapter在滾動時顯示已顯示的項目

基本上,我想列出一個問題,每個問題(無線電,複選框,文本,數字)的不同類型。 生成listview時,顯示正常。但是當我向下滾動時,頂部的物品會在底部重新生成。

我的代碼是這樣的:

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

    View someView = convertView; 

    //get question type 
    String type = questions.get(position)[2]; 

    //declare viewholder 
    final ViewHolder holder; 
    Log.i("Position", Integer.toString(position)); 

    if (someView == null) { 
    Log.i("convertView", "null"); 
    holder = new ViewHolder(); 

    LayoutInflater inflater = (LayoutInflater) context 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    someView = inflater.inflate(R.layout.list_survey, parent, false); 

    TextView textView = (TextView) someView.findViewById(R.id.surveyQuestion); 
    textView.setText(questions.get(position)[1]); 

    LinearLayout optionContainer = (LinearLayout) someView.findViewById(R.id.surveyOption); 

    int size = options.get(position).size(); 

    //radio button 
    if (type.equals("radio")) { 

     RadioGroup group = new RadioGroup(this.context); 
     RelativeLayout.LayoutParams groupParam = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); 
     optionContainer.addView(group, groupParam); 
     RadioButton radio = null; 

     ArrayList<RadioButton> radios = new ArrayList<RadioButton>(); 

     for (int i=0; i<size; i++){ 
      radio = new RadioButton(this.context); 
      radio.setId(i+1); 
      radio.setText(options.get(position).get(i)[1]); 
      group.addView(radio); 
      radios.add(radio); 
     }  
     group.setOnCheckedChangeListener(new OnCheckedChangeListener() 
     { 
      public void onCheckedChanged(RadioGroup group, int checkedId) { 
       //Model element = (Model)group; 
      } 
     }); 

     holder.radiogroup = group; 
     holder.radiobuttons = radios; 

    //checkbox 
    } else if (type.equals("check")) { 
     CheckBox checkbox = null; 

     ArrayList<CheckBox> checks = new ArrayList<CheckBox>(); 

     for (int i=0; i<size; i++){ 
      checkbox = new CheckBox(this.context); 
      checkbox.setId(i+1); 
      checkbox.setText(options.get(position).get(i)[1]); 
      optionContainer.addView(checkbox); 
      checks.add(checkbox); 
     } 

     holder.checkboxes = checks; 

    //textfield 
    } else if (type.equals("txt")) { 
     EditText field = null; 

     ArrayList<EditText> fields = new ArrayList<EditText>(); 

     for (int i=0; i<size; i++){ 
      field = new EditText(this.context); 
      field.setId(i+1); 
      field.setHint(options.get(position).get(i)[1]); 
      optionContainer.addView(field); 
      fields.add(field); 
     } 

     holder.edittext = fields; 
    //numeric 
    } else if (type.equals("num")) { 
     EditText field = null; 

     ArrayList<EditText> fields = new ArrayList<EditText>(); 

     for (int i=0; i<size; i++){ 
      field = new EditText(this.context); 
      field.setId(i+1); 
      field.setHint(options.get(position).get(i)[1]); 
      field.setInputType(InputType.TYPE_CLASS_NUMBER); 
      optionContainer.addView(field); 
      fields.add(field); 
     } 

     holder.edittext = fields; 
    } 

    someView.setTag(holder); 

    } else { 
    Log.i("convertView", "not null"); 
    holder = (ViewHolder) someView.getTag(); 
    } 


    return someView; 
} 

的viewHolder類是在這裏:

//viewHolder 
static class ViewHolder { 
    ArrayList<CheckBox> checkboxes; 
    ArrayList<EditText> edittext; 
    RadioGroup radiogroup; 
    ArrayList<RadioButton> radiobuttons;  
} 

我在做什麼錯?

我真的很感謝你的幫助。我已經搜索了一些其他的解決方案,但我無法在我的代碼上工作。

感謝

+0

**只是**第一項?你能否粘貼你如何創建自定義的'ArrayAdapter'實例? – nKn

+0

對不起,我只注意到第一次出現,但後來我看到了你的帖子並重新檢查了它。很顯然,每次滾動屏幕時,都會調出屏幕上的項目並替換列表中的下一個項目。 – alfa

+0

然後@ LukaCiko的回答是正確的。你只是簡單地管理標籤,但是你並沒有更新'ViewHolder'裏面的View。 – nKn

回答

3

這是因爲您使用的是convertViewViewHolder不正確。當您向下滾動時,視圖將被回收並且converView不會爲空。該ViewHolder模式通常這樣使用:

public View getView(int position, View convertView, ViewGroup parent) { 
    if(convertView == null) { 
     inflate the view 
     create a ViewHolder and store the necessary views in it 
     use setTag to store the ViewHolder in the convertView 
    } 
    else { 
     use getTag to get the ViewHolder 
    } 
    update the views // <- you are not doing this when convertView != null 
} 

之所以使用convertView/ViewHolder模式是視圖列表通常有佈局相同,但它們顯示不同的數據。本質上,convertView(如果不爲空)是以前在列表中使用的視圖,必須轉換爲顯示此位置的正確數據。通過重複使用它,您可以避免昂貴的佈局膨脹。 ViewHolder是一個進一步的優化,您可以避免昂貴的findViewById調用。

+0

'昂貴的findView調用'通過它的id在'ViewGroup'中查找'View'有多昂貴?這是一個簡單的迭代... – gunar

+0

好像它是這樣的,但它必須遞歸遍歷'ViewGroup'層次結構。根據我的經驗,「ViewHolder'優化」具有顯着的效果,至少在佈局不是非常基本時。 – LukaCiko

+0

我理解你的解釋中的基本概念,但我仍然不清楚應該怎麼做才能使其工作。更新觀點意味着什麼? 我應該從if語句中生成視圖的代碼嗎?如果是這樣,我應該在if語句中將狀態保存到viewHolder中? – alfa