Такое поведение возникает потому, что 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 (Интерактивные строки)