所以我之前遇到了这个问题,很自然地,我在here上寻求帮助。Luksprog的回答很棒,因为我不知道ListView和GridView是如何使用回收视图优化自己的。因此,在他的建议下,我能够改变向GridView添加视图的方式。问题是,现在我有一些不合理的东西。这是来自我的BaseAdapter
的getView
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.day_view_item, parent, false);
}
Log.d("DayViewActivity", "Position is: "+position);
((TextView)convertView.findViewById(R.id.day_hour_side)).setText(array[position]);
LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.day_event_layout);
//layout.addView(new EventFrame(parent.getContext()));
TextView create = new TextView(DayViewActivity.this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 62, getResources().getDisplayMetrics()), 1.0f);
params.topMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
params.bottomMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
create.setLayoutParams(params);
create.setBackgroundColor(Color.BLUE);
create.setText("Test");
//the following is my original LinearLayout.LayoutParams for correctly setting the TextView Height
//new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics()), 1.0f)
if(position == 0) {
Log.d("DayViewActivity", "This should only be running when position is 0. The position is: "+position);
layout.addView(create);
}
return convertView;
}
}
问题是当我滚动时,这种情况发生了,而不是在位置0上...看起来像是位置6和位置8,加上位置8中的两个。现在我仍然在尝试使用ListView和GridView的诀窍,所以我不明白为什么会发生这种情况。我提出这个问题的一个主要原因是为了帮助那些可能不知道ListView和GridView的循环视图,或者这个article所说的ScrapView机制的人。
稍后编辑
添加链接到google IO talk,这基本上就是理解ListView工作原理所需的全部内容。Link在评论中死了。所以user3427079很友好地更新了这个链接。Here它是为了方便访问。
发布于 2013-01-01 15:24:30
起初,我也不知道列表视图的回收和转换视图的使用机制,但经过一整天的研究,我通过参考来自android.amberfog的一张图片,基本上理解了列表视图的机制
每当您的listview被适配器填充时,它基本上显示了listview可以在屏幕上显示的行数,即使您滚动列表,行数也不会增加。这就是android使用的诀窍,让listview更高效、更快速地工作。现在listview的内部故事引用了图像,正如您所看到的,最初listview有7个可见项目,然后,如果您向上滚动直到项目1不再可见,getView()会将此视图(即item1)传递给回收器,您可以使用
System.out.println("getview:"+position+" "+convertView);
在你的
public View getView(final int position, View convertView, ViewGroup parent)
{
System.out.println("getview:"+position+" "+convertView);
ViewHolder holder;
View row=convertView;
if(row==null)
{
LayoutInflater inflater=((Activity)context).getLayoutInflater();
row=inflater.inflate(layoutResourceId, parent,false);
holder=new PakistaniDrama();
holder.tvDramaName=(TextView)row.findViewById(R.id.dramaName);
holder.cbCheck=(CheckBox)row.findViewById(R.id.checkBox);
row.setTag(holder);
}
else
{
holder=(PakistaniDrama)row.getTag();
}
holder.tvDramaName.setText(dramaList.get(position).getDramaName());
holder.cbCheck.setChecked(checks.get(position));
return row;
}
你会在你的日志中注意到,最初,convertview对于所有可见的行都是空的,因为最初在回收器中没有视图(即项目),所以你的getView()为每个可见的项目创建了一个新的视图,但是当你向上滚动并且项目1移出屏幕时,它将被发送到回收器,以及它的当前状态(例如,文本‘TextView’,或者在我的例子中,如果复选框被选中,它将与视图相关联并存储在回收器中)。
现在,当您向上/向下滚动时,列表视图不会创建新视图,它将使用回收器中的视图。在你的Logcat中,你会注意到' convertview‘不是空的,这是因为你的新项目8将使用convertview绘制,也就是说,基本上它从回收器中获取项目1视图,并在其位置膨胀项目8,你可以在我的代码中观察到这一点。如果你有一个复选框,如果你在位置0选中它(假设item1有一个复选框,你选中了它),那么当你向下滚动时,你会看到第8项复选框已经被选中,这就是为什么listview重新使用相同的视图,而不是因为性能优化而为你创建新的视图。
重要的事情
1。切勿将列表视图的layout_height
和layout_width
设置为wrap_content
,因为getView()
会强制您的适配器获取一些用于在列表视图中绘制的用于测量视图高度的子项,并可能导致一些意想不到的行为,如在列表不是scrolled.always的情况下返回convertview,使用match_parent
或固定宽度/高度。
2。如果你想在列表视图之后使用一些布局或视图,并且如果我将layout_height
设置为fill_parent
,那么列表视图将不会在屏幕上显示出来。因此,最好将列表视图放入layout.For示例线性布局中,并根据需要设置该布局的高度和宽度,并将列表视图的 height 和 width 属性设置为as布局(例如,如果布局宽度为320,高度为280),则列表视图应具有相同的宽度高度<>E232>和<代码>E133宽度<代码>E234。这将告诉getView()要呈现的视图的确切高度和宽度,getView()不会一次又一次地调用一些随机的行,并且不会发生其他问题,比如在滚动之前返回转换视图。我自己测试过这个,除非我的列表视图在lineaLayout中,它也有重复视图调用和转换视图为等问题,将列表视图放在LinearLayout中对我来说就像变魔术一样。(不知道为什么)
01-01 14:49:36.606: I/System.out(13871): getview 0 null
01-01 14:49:36.636: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.636: I/System.out(13871): getview 1 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 2 android.widget.RelativeLayout@406082c0
01-01 14:49:36.646: I/System.out(13871): getview 3 android.widget.RelativeLayout@406082c0
01-01 14:49:36.656: I/System.out(13871): getview 4 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 5 android.widget.RelativeLayout@406082c0
01-01 14:49:36.666: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.696: I/System.out(13871): getview 0 android.widget.RelativeLayout@406082c0
01-01 14:49:36.706: I/System.out(13871): getview 1 null
01-01 14:49:36.736: I/System.out(13871): getview 2 null
01-01 14:49:36.756: I/System.out(13871): getview 3 null
01-01 14:49:36.776: I/System.out(13871): getview 4 null
但是现在问题解决了,我知道,我不太擅长解释,但是我花了一整天的时间去理解,所以我认为其他像我一样的初学者可以从我的经验中获得帮助,我希望现在你们能对ListView框架的工作原理有一点了解,因为它真的很混乱和棘手,所以初学者发现理解它有太多的问题。
发布于 2014-04-14 18:56:12
注意,在Holder模式中,如果您在Holder对象中设置位置,则每次都应设置它,例如:
@Override
public final View getView(int position, View view, ViewGroup parent) {
Holder holder = null;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) App.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(getContainerView(), parent, false);
holder = getHolder(position, view, parent);
holder.setTag(tag);
view.setTag(holder);
} else {
holder = (Holder) view.getTag();
}
holder.position = position;
draw(holder);
return holder.getView();
}
这是一个抽象类的示例,其中
getHolder(position, view, parent);
执行的所有设置操作都是针对
ImageViews, TextViews, etc..
发布于 2015-12-19 21:24:35
使用Holder模式,您可以实现您想要的功能:
You can find description of this pattern here:
当您向下滚动屏幕并隐藏列表视图项目上方时,会发生列表视图的回收。它们被重用来显示新的列表视图项。
https://stackoverflow.com/questions/11945563
复制相似问题