Пользовательский адаптер ListView, странное поведение ImageView - PullRequest
4 голосов
/ 18 марта 2012

У меня есть пользовательский ListView Adapter, с помощью которого я создаю строки для списка.Моя проблема, однако, в том, что он, похоже, не отличает ImageView друг от друга.Кажется, что я случайно выбираю ImageViews, чтобы встать на место, когда я прокручиваю вверх и вниз.Текстовая информация (опущена из этого фрагмента) не прерывается.Это работает, как и следовало ожидать.

Вот соответствующий метод моего Adapter:

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

    if( v == null )
    {
      LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      v = vi.inflate( R.layout.generic_row, null );
    }

    // find the image
    ImageView favImage = (ImageView)v.findViewById( R.id.toggle_favorite );

   // when clicked...
   favImage.setOnClickListener( new OnClickListener() {

     @Override
     public void onClick( View v )
     {
       // make the gray star a yellow one
       int newImage = R.drawable.ic_star_yellow_embossed;
       ((ImageView)v).setImageBitmap(BitmapFactory.decodeResource(getContext().getResources(), newImage));
     }

   });

  return v;
  }

Ответы [ 2 ]

3 голосов
/ 18 марта 2012

Такое поведение возникает потому, что ListView перерабатывает представления строк при прокрутке списка вверх и вниз, и из-за этого вы получаете строки, на которые воздействовал пользователь (изображение было изменено) в том положении, в котором изображение должно быть неизменным. Чтобы избежать этого, вам нужно каким-то образом удерживать статус ImageView для каждой строки в списке и использовать этот статус для установки правильного изображения в методе getView(). Поскольку вы не сказали, как именно вы реализовали свой адаптер, я покажу вам простой пример.

Прежде всего вы должны сохранить свои статусы ImageView. Я использовал ArrayList<Boolean> в качестве члена пользовательского адаптера, если позиция (соответствующая позиции строки в списке) в этом списке равна false, тогда изображение является значением по умолчанию, в противном случае, если оно равно true, то пользователь щелкнул по нему, и мы должны поставить новое изображение:

private ArrayList<Boolean> imageStatus = new ArrayList<Boolean>();

В вашем конструкторе адаптера инициализируйте этот список. Например, если вы добавили в свой адаптер список чего-либо, вы должны сделать ваш imageStatus размером с этот список и заполнить false (статус по умолчанию / старт):

//... initialize the imageStatus, objects is the list on which your adapter is based
for (int i = 0; i < objects.size(); i++) {
    imageStatus.add(false);
}

Тогда в вашем getView() методе:

View v = convertView;

            if (v == null) {
                LayoutInflater vi = (LayoutInflater) getContext()
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.adapters_adapter_with_images, null);
            }

            // find the image
            ImageView favImage = (ImageView) v
                    .findViewById(R.id.toggle_favorite);
            // Set the image bitmap. If the imageStatus flag for this position is TRUE then we
            // show the new image because it was previously clicked by the user
            if (imageStatus.get(position)) {
                int newImage = R.drawable.ic_star_yellow_embossed;
                favImage.setImageBitmap(BitmapFactory.decodeResource(
                        getContext().getResources(), newImage));
            } else {
                // If the imageStatus is FALSE then we explicitly set the image
                // back to the default because we could be dealing with a
                // recycled ImageView that has the new image set(there is no need to set a default drawable in the xml layout)                                       
                int newImage = R.drawable.basket_empty; //the default image
                favImage.setImageBitmap(BitmapFactory.decodeResource(
                        getContext().getResources(), newImage));
            }
            // when clicked... we get the real position of the row and set to TRUE
            // that position in the imageStatus flags list. We also call notifyDataSetChanged
            //on the adapter object to let it know that something has changed and to update!
            favImage.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Integer realPosition = (Integer) v.getTag(); //get the position from the view's tag
                    imageStatus.set(realPosition, true); //this position has been clicked be the user
                    adapter.notifyDataSetChanged(); //notify the adapter
                }

            });
            // set the position to the favImage as a tag, we later retrieve it
            // in the onClick method
            favImage.setTag(new Integer(position));
            return v;

        }

Это должно работать хорошо, если вы не планируете динамически изменять список (удалять / добавлять строки), в противном случае вам придется также позаботиться об изменении этого списка imageStatus, чтобы отразить изменения. Вы не сказали, какими были ваши данные строки, другой подход (и правильный подход, если вы планируете что-то делать, если пользователь щелкает это изображение (помимо его изменения)), состоит в том, чтобы включить статус изображения в модель данных строки. В связи с этим вот несколько уроков:

Android ListView Advanced Interactive или Выдержка Commonsware-Android (Интерактивные строки)

2 голосов
/ 18 марта 2012

вам нужно определить изображение по умолчанию сразу после нахождения его ссылки:

// find the image
ImageView favImage = (ImageView)v.findViewById( R.id.toggle_favorite );
//setting to default
favImage.setImageResource(R.drawable.default_image);
// when clicked...
favImage.setOnClickListener....

вам нужно сделать это, потому что после изменения изображения и прокрутки ListView оно появляется снова, потому что ListView перезагружает элементПросмотры.Поэтому вам нужно определить его в getView , чтобы использовать изображение по умолчанию при прокрутке списка

...