【问题标题】:BaseAdapter selecting item and processing issueBaseAdapter 选择项目和处理问题
【发布时间】:2012-07-03 17:38:53
【问题描述】:

我有一个ListView,它扩展了BaseAdapter。我有一个 data[] 数组。 ListView 膨胀并正确填充。我要做的是在用户选择项目时在列表项上显示ImageView(基本上是膨胀视图右侧的检查图像)并且如果选择了以前的项目,我只是隐藏它ImageView。这也很好用。

但在我选择一个新项目并来回滚动后,我看到了奇怪的行为,检查图像有时在多个列表项目中可见,或者隐藏在当前选择的实际项目中。有人可以帮忙解释一下我做错了什么吗?

我在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];
  }

}

【问题讨论】:

    标签: android android-listview inflate baseadapter android-adapter


    【解决方案1】:

    但是在我选择一个新项目并来回滚动后,我发现很奇怪 行为,检查图像有时在多个列表项中可见 或隐藏在当前选中的实际项目中。

    这很可能是因为您为convertView 设置点击侦听器的方式。您设置OnCLickListener 仅适用于convertViewnull 的情况,但当您上下滚动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;
    }
    

    【讨论】:

    • @lumpawire 您可以使用convertView 上的侦听器完成此操作,但在您的特定情况下,就像我向您展示的那样更容易。使用您的代码,您可以在convertViewnull(最有可能在首次显示列表时)时convertView 充气并在其上设置一个侦听器。但是,当您向下滚动 ListView 时,convertView 不为空(此时您不会膨胀新的 convertView 并且您也没有设置新的侦听器,而是使用旧的侦听器)。问题是这个老听众是(或可能)指向错误的ImageView,所以你最终会出现错误的行为。
    • @lumpawire 例如,尝试(我不保证它会起作用)在convertView if-else 子句之后设置监听器(对于null)。此外,不建议您使用您的方法,因为您坚持使用视图来识别您想要的视图,这有点困难(嗯,不是那么困难,但应该避免)在回收View 中处理。
    猜你喜欢
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-16
    • 2012-06-07
    • 2012-09-06
    相关资源
    最近更新 更多