3

我有一個ListView它延伸BaseAdapter。我有一個數據[]數組。 ListView膨脹並正確填充。我想要做的是在用戶選擇該項目時,在列表項目(基本上是充氣視圖右側的檢查圖像)上顯示一個ImageView,並且如果選擇了之前的項目,我只需隱藏該ImageView。這工作也很好。BaseAdapter選擇項目和處理問題

但是,當我選擇一個新項目並來回滾動時,我看到奇怪的行爲,檢查圖像有時在多個列表項中可見,或隱藏在當前選定的實際項目中。有人能幫助解釋我做錯了什麼嗎?

我在onCreate方法這兩條線:

adap = new EfficientAdapter(this); 
    lstview.setAdapter(adap); 

和適配器代碼:

public static class EfficientAdapter extends BaseAdapter implements Filterable { 
    private LayoutInflater mInflater; 
    private Context context; 
    private ImageView CurrentSelectedImageView; 
    private Integer CurrentPosition = 14; 


    public EfficientAdapter(Context context) { 
    mInflater = LayoutInflater.from(context); 
    this.context = context; 
    } 


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

    ViewHolder holder; 

    //Log.e("TAG",String.valueOf(position)); 

    if (convertView == null) { 
     convertView = mInflater.inflate(R.layout.adaptor_content, null); 

     holder = new ViewHolder(); 
     holder.textLine = (TextView) convertView.findViewById(R.id.txtCategoryCaption); 
     holder.iconLine = (ImageView) convertView.findViewById(R.id.iconLine); 
     holder.imgCheckbox = (ImageView) convertView.findViewById(R.id.imgCheck); 


     //If the CurrentPosition == position then make the checkbox visible else dont. 
     if (CurrentPosition == position){ 

     holder.imgCheckbox.setVisibility(View.VISIBLE); 
     }else{ 
     holder.imgCheckbox.setVisibility(View.INVISIBLE); 
     } 


     final ImageView Checkbox = holder.imgCheckbox; 

     //Now if the list item is clicked then set the position as the current item and make the checkbox visible. 

     convertView.setOnClickListener(new OnClickListener() { 
     private int pos = position; 

     @Override 
     public void onClick(View v) { 
      if (CurrentSelectedImageView!=null){ 
       CurrentSelectedImageView.setVisibility(View.INVISIBLE); 
      } 
      Checkbox.setVisibility(View.VISIBLE); 
      CurrentSelectedImageView = Checkbox; 
      CurrentPosition = pos; 

     } 
     }); 

     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 


     int id = context.getResources().getIdentifier("nodeinsert", "drawable", context.getString(R.string.package_str)); 
     if (id != 0x0) { 
      mIcon1 = BitmapFactory.decodeResource(context.getResources(), id); 
     } 

     holder.iconLine.setImageBitmap(mIcon1); 
     holder.textLine.setText(String.valueOf(data[position])); 


    if (CurrentPosition == position){ 
     Log.e("TAG",CurrentPosition + "---" + String.valueOf(position)); 
     holder.imgCheckbox.setVisibility(View.VISIBLE); 
    }else{ 
     holder.imgCheckbox.setVisibility(View.INVISIBLE); 
    } 


    return convertView; 
    } 



    static class ViewHolder { 
    TextView textLine; 
    ImageView iconLine; 
    ImageView imgCheckbox; 
    } 

    @Override 
    public Filter getFilter() { 
    // TODO Auto-generated method stub 
    return null; 
    } 

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

    @Override 
    public int getCount() { 
    // TODO Auto-generated method stub 
    return data.length; 
    } 

    @Override 
    public Object getItem(int position) { 
    // TODO Auto-generated method stub 
    return data[position]; 
    } 

} 

回答

5

但之後我選擇一個新的項目,向後滾動來回回我看到奇怪 行爲,檢查圖像有時在多個列表項 中可見或隱藏在當前選定的實際項目中。

這很可能是因爲您爲convertView設置點擊偵聽器的方式而發生的。只有當convertViewnull時,您纔會設置OnCLickListener,但是當您上下滾動ListView時,行將被回收,並且最終會以與其他行相同的偵聽器結束。

無論如何,如果您只希望只有一行圖像可見,則可以採用更簡單的方法。首先,您應該將OnCLickListener放在convertView上,並在ListView元素上使用OnItemClickListener。從這個偵聽器回調,你要修改的行:

lstview.setOnItemClickListener(new OnItemClickListener() { 

      @Override 
      public void onItemClick(AdapterView<?> l, View v, int position, 
        long id) { 
       View oldView = l.getChildAt(adap.getSelectedPosition()); 
       ImageView img; 
       if (oldView != null && adap.getSelectedPosition() != -1) { 
        img = (ImageView) oldView.findViewById(R.id.imageView1); 
        img.setVisibility(View.INVISIBLE); 
       } 
       img = (ImageView) v.findViewById(R.id.imageView1); 
       img.setVisibility(View.VISIBLE); 
       adap.setSelectedPosition(position); 
      } 
     }); 

然後修改適配器這樣的:

// a field in the adapter 
private int mSelectedPosition = -1; 

// getter and setter methods for the field above 
public void setSelectedPosition(int selectedPosition) { 
    mSelectedPosition = selectedPosition; 
    notifyDataSetChanged(); 
} 

public int getSelectedPosition() { 
    return mSelectedPosition; 
} 

// and finally your getView() method 
public View getView(final int position, View convertView, ViewGroup parent) { 
    ViewHolder holder; 
    if (convertView == null) { 
     convertView = mInflater.inflate(R.layout.adaptor_content, parent, false); 
     holder = new ViewHolder(); 
     holder.textLine = (TextView) convertView.findViewById(R.id.txtCategoryCaption); 
     holder.iconLine = (ImageView) convertView.findViewById(R.id.iconLine); 
     holder.imgCheckbox = (ImageView) convertView.findViewById(R.id.imgCheck); 
     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 
    if (mSelectedPosition == position) { 
    holder.imgCheckbox.setVisibility(View.VISIBLE); 
    } else { 
    holder.imgCheckbox.setVisibility(View.INVISIBLE); 
    }  
     // what is the point of this call?! 
     // you should move this to another place(like the adapter's constructor), the getIdentifier() 
     // method is a bit slow and you call it each time the adapter calls getView() 
     // you should never use it in the getView() method(), especially as all you do is get the id of the same drawable again and again 
     int id = context.getResources().getIdentifier("nodeinsert", "drawable", context.getString(R.string.package_str)); 
     // ?!? 
     if (id != 0x0) { 
      mIcon1 = BitmapFactory.decodeResource(context.getResources(), id); 
     } 
     holder.iconLine.setImageBitmap(mIcon1); 
     holder.textLine.setText(String.valueOf(data[position])); 
     return convertView; 
} 
+0

@lumpawire你可以有一個聽衆做了它的'convertView'但在您的特定情況就好像我向你展示的那樣。使用你的代碼,當'convertView'爲'null'時(最有可能當列表第一次被顯示時),你使用'convertView'並設置一個監聽器** only **。但是,當您向下滾動ListView時,convertView不爲null(此時,您不會爲新的'convertView'充氣,並且您不會設置新的偵聽器,您有舊的偵聽器)。問題是這個老的監聽器是(或可能)指向錯誤的'ImageView',所以你最終的行爲是錯誤的。 – Luksprog

+0

@lumpawire例如,嘗試(我不保證它會起作用)在'convertView'' if'-'else'子句(用於'null')之後設置監聽器。當你堅持觀看來識別你想要的觀點時,你也不建議你採用這種方法,因爲在回收「視圖」中處理這個過程有點困難(當然,這並不難,但應該避免)。 – Luksprog