问题描述
我有一个自定义的的ListView
适配器
,与我的列表创建行。我的问题是,虽然,它似乎并没有被区分的ImageView
S,从对方。这似乎是随机挑选 ImageViews
来扔掉到位,我向上和向下滚动。文本信息(这段代码省略)不破。它的工作原理为人们所期望的。
下面是我的适配器
的相关方法:
公开查看getView(INT位置,查看convertView,父母的ViewGroup)
{
视图V = convertView;
如果(V == NULL)
{
LayoutInflater VI =(LayoutInflater)的getContext()getSystemService(Context.LAYOUT_INFLATER_SERVICE)。
V = vi.inflate(R.layout.generic_row,NULL);
}
//发现图像
ImageView的favImage =(ImageView的)v.findViewById(R.id.toggle_favorite);
//当点击...
favImage.setOnClickListener(新OnClickListener(){
@覆盖
公共无效的onClick(视图v)
{
//使灰色明星黄色的
INT newImage = R.drawable.ic_star_yellow_embossed;
((ImageView的)V).setImageBitmap(BitmapFactory.de codeResource(的getContext()getResources(),newImage));
}
});
返回伏;
}
这种行为出现,因为的ListView
回收行的意见,您滚动列表向上和向下,并因为这个,你得到的用户采取了行动上的行(图像被改变)的位置是图像应该是不变。为了避免这种情况,你就必须以某种方式持有的地位的ImageView
列表中的每一行,并使用该状态设置正确的图像中的 getView()
方法。因为你没有说你是如何准确地实现您的适配器,我会告诉你一个简单的例子。
首先,你应该存储的ImageView
你的状态。我用了一个的ArrayList<布尔>
作为自定义适配器中的一员,如果位置(对应于列表中的行的位置),在这个列表假
则图像是默认的,否则,如果它是真
然后用户点击它,我们应该把新形象:
私人的ArrayList<布尔> imageStatus =新的ArrayList<布尔>();
在自定义适配器的构造函数初始化列表中。例如,如果你在你的适配器把东西名单,那么你应该让你的 imageStatus
那样大名单,充满了假
(默认/启动状态):
// ...初始化imageStatus,对象是在其上适配器基于名单
的for(int i = 0; I< objects.size();我++){
imageStatus.add(假);
}
然后在你的 getView()
方法:
视图V = convertView;
如果(V == NULL){
LayoutInflater VI =(LayoutInflater)的getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
V = vi.inflate(R.layout.adapters_adapter_with_images,NULL);
}
//发现图像
ImageView的favImage =(ImageView的)V
.findViewById(R.id.toggle_favorite);
//设置图像的位图。如果imageStatus标志这个位置,然后是真的,我们
//显示新的形象,因为它是previously用户点击
如果(imageStatus.get(位置)){
INT newImage = R.drawable.ic_star_yellow_embossed;
favImage.setImageBitmap(BitmapFactory.de codeResource(
的getContext()getResources(),newImage))。
} 其他 {
//如果imageStatus为假,那么我们明确地设置图像
//返回到默认的,因为我们可以处理一个
//回收的ImageView有新的图像集(有没有必要设置在XML布局中的默认绘制)
INT newImage = R.drawable.basket_empty; //默认图像
favImage.setImageBitmap(BitmapFactory.de codeResource(
的getContext()getResources(),newImage))。
}
//点击后...我们得到该行的实际位置,并设置为TRUE
//在imageStatus标志列表中的位置。我们也呼吁notifyDataSetChanged
//适配器对象上,让它知道的东西已经改变,并更新!
favImage.setOnClickListener(新OnClickListener(){
@覆盖
公共无效的onClick(视图v){
整数realPosition =(整数)v.getTag(); //从视图的标签位置
imageStatus.set(realPosition,真正的); //这个位置已经被点击是用户
adapter.notifyDataSetChanged(); //通知适配器
}
});
//设置位置到favImage作为标记,我们以后检索
//在onclick方法
favImage.setTag(新的整数(位置));
返回伏;
}
这应该足够了,如果你不打算动态修改列表(删除/添加行),否则你将不得不采取的也是修改 imageStatus $ C的该名单护理$ C>以反映更改。你没有说什么你行的数据,另一种方法(和正确的,如果你打算做一些事情,如果用户点击该图像(除了改变吧))是将在该行的数据模型图像的状态。对此这里有一些教程:
Android的ListView的高级交互式或 Commonsware-的Android摘录(交互式行)
I have a custom ListView
Adapter
, with which I'm creating rows for a list. My problem is though, that it doesn't seem to be distinguishing the ImageView
s, from each other. It seems to be randomly picking ImageViews
to chuck into place as I scroll up and down. The text information (omitted from this snippet) does not break. It works as one would expect.
Here is the relevant method of my 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;
}
That behavior appears because the ListView
recycles the row views as you scroll the list up and down, and because of this you get rows that were acted on by the user(the image was changed) in position were the image should be unmodified. To avoid this you'll have to somehow hold the status of the ImageView
for every row in the list and use this status to set up the correct image in the getView()
method. Because you didn't say how exactly did you implement your adapter I will show you a simple example.
First of all you should store your the statuses of the ImageView
. I used an ArrayList<Boolean>
as a member of the custom adapter, if the position(corresponding to the row's position in the list) in this list is false
then the image is the default one, otherwise if it is true
then the user clicked it and we should put the new image:
private ArrayList<Boolean> imageStatus = new ArrayList<Boolean>();
In your custom adapter constructor initialize this list. For example if you put in your adapter a list of something then you should make your imageStatus
as big as that list and filled with false
(the default/start status):
//... initialize the imageStatus, objects is the list on which your adapter is based
for (int i = 0; i < objects.size(); i++) {
imageStatus.add(false);
}
Then in your getView()
method:
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;
}
This should work well if you don't plan to dynamically modify the list(remove/add rows), otherwise you'll have to take care of also modifying that list of imageStatus
to reflect the changes. You didn't say what was your row data, another approach(and the right one if you plan to do something if the user clicks that image(besides changing it)) is to incorporate the status of the image in the row's data model. Regarding this here are some tutorials:
Android ListView Advanced Interactiveor Commonsware-Android Excerpt (Interactive rows)
这篇关于自定义的ListView适配器,奇怪的ImageView的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!