我有一个自定义ListView
Adapter
,我正在为列表创建行。但问题是,它似乎并没有将ImageView
s彼此区分开来。当我向上和向下滚动时,它似乎随机地挑选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;
}
答案 0 :(得分:3)
出现这种情况是因为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 Excerpt(交互行)
答案 1 :(得分:2)
您需要在找到其参考后立即定义默认图像:
// 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 中定义它以在滚动列表时使用默认图像