我从listview / getChildAt方法中获得了一些奇怪的行为。
我有一个HashSet,iconsToUpdate,已在数据库中更改过的图标。我想迭代可见行,看看是否需要更新任何图标以反映新图标。我不需要测试当前不在视图中的图标,因为它们在渲染时会被正确绘制。
我的问题是getChildAt在看起来不应该返回null。我知道getChildAt只能返回当前可见的视图,但是对于某些可见的行,它返回null。
这是我的代码,它迭代可见的行:
Logger.debug("First visible index: " + f_listView.getFirstVisiblePosition());
Logger.debug("Last visible index: " + f_listView.getLastVisiblePosition());
for (int i = f_listView.getFirstVisiblePosition(); i <= f_listView.getLastVisiblePosition(); i++) {
String tag = "asdf"; // Remove when bug is fixed.
if (f_listView == null) {
Logger.debug("f_listView is null");
} else if (f_listView.getChildAt(i) == null) {
Logger.debug("Child at index " + i + " is null");
} else {
tag = (String) f_listView.getChildAt(i).getTag();
Logger.debug("Successful at index " + i + ", tag is: " + tag);
}
if (iconsToUpdate.contains(tag)) {
setIcon(i, f_aim.getInHouseIcon(tag));
}
}
这是与此循环运行相对应的日志:
D/...: First visible index: 3
D/...: Last visible index: 8
D/...: Successful at index 3, tag is: ...
D/...: Successful at index 4, tag is: ...
D/...: Successful at index 5, tag is: ...
D/...: Child at index 6 is null
D/...: Child at index 7 is null
D/...: Child at index 8 is null
应该注意的是,正确报告了第一个和最后一个可见索引,因为我在运行它时正在查看第3-8行。第6,7,8行正确呈现。如果它们为空,它们是如何显示的?
此外,我不知道这是否重要,但当我位于列表视图的顶部时,第5行是最后一行。
关于为什么将这些行返回为null的任何信息都将非常感激。
谢谢!
答案 0 :(得分:134)
listView.getChildAt(i)的工作原理,其中0是第一个可见行,(n-1)是最后一个可见行(其中n是您看到的可见视图数)。
get last / first visible返回您拥有的dataAdapter中的位置。所以你从第3个位置开始,看起来像是6个可见的视图,那么当获得6-8个位置时,你就会得到null。
在你的例子中,getChildAt(0)将返回位置3.我通常做的是将位置存储在我的视图中,这样如果我需要值,我可以在以后查找我的dataAdapter。
我认为你的for循环应该是这样的:
for (int i = 0; i <= f_listView.getLastVisiblePosition() - f_listView.getFirstVisiblePosition(); i++)
希望这有帮助。
答案 1 :(得分:3)
当您致电listView1.getLastVisiblePosition()
和listView1.getFirstVisiblePosition()
时,listview
会返回列表视图中部分可见的项目的位置。例如,第一项可以是一半可见,最后一项可以是一半可见。在这种情况下,即使您可以在列表视图中看到项目的一部分,适配器尚未调用该项目的getView()
函数,因此该项目仍被视为空。
答案 2 :(得分:0)
他们可能部分可见。但是当getView()尝试回收视图时,它会获得完全可见的视图,而其他视图则将它们视为null。例如,如果您滚动列表并且顶部项目部分可见且底部部分可见,那么这些是空值但您仍然可以看到它们。
答案 3 :(得分:0)
我在OnListItemClickListener()中尝试过,但是失败了。最后我在listview的定制适配器上做了一些修改。在getView()中,我将clickListener应用于我经常添加到列表中的项目。那里做所有必需的功能。这是我的代码,我在列表中添加了Image View,因此在imageview上应用了listener。
我认为它会帮助那些想要在选择特定列表项时更改颜色的人。去吧..
在自定义适配器的getView()中 // - - - - - - - - - - - - - - - - -码 - - - - - - - ----------------------------
LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.icon_image_layout, parent, false); ImageView imageView = (ImageView) rowView.findViewById(R.id.Icon_ImageView); imageView.setClickable(true); final int pos=position; imageView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub // TODO Auto-generated method stub try{ if(previous_view!=null) previous_view.setBackgroundColor(Color.WHITE); }catch (Exception e) { System.out.println("Exception Occurs Previous View"); } v.setBackgroundColor(Color.RED); MainActivity.imageView.setImageResource(MainActivity.Image_Name[pos]); previous_view=v; return false; } });
答案 4 :(得分:0)
我知道这是很老的帖子。但我正在回答,因为人们仍然在寻找ListView getChildAt()
空指针异常的解决方法。
这是因为ArrayApdater因为高度而正在REMOVING和RECYCLING ListView上尚未显示的视图。因此,如果您有10个项目视图,并且ListView可以在当时显示4 - 5:
适配器删除位置5到9的项目视图,这样任何adapter.getChildAt(5... to 9)
的尝试都会导致空指针异常
适配器还可以循环显示项目视图,这样当您向下滚动到5到9时,您在位置3上所做的任何引用都会丢失,以及您在第3个位置上进行的任何输入(EditText,Checkbox等) 。)当你向下滚动到5到9时将被回收,并且将在以后的另一个位置(从位置1,2或3等)重新使用具有相同值的
我发现控制它的唯一方法是忘记获取视图并拥有:
属性HashMap<Integer, ImageView> iconViews
或您希望处理要用于列表中每个项目的值的任何类型。对于item->getId()
或position
等项,第一种类型必须是唯一的。在构造函数中使用new HashMap<>()
初始化它;
在getViews中iconViews.put(position, iconView);
阻止适配器使用回收的convertView,删除条件if(convertView == null)
,以便适配器始终为全新的视图实例充气。因为视图实例每次都是新的,所以每次都必须从HashMap设置值,就好像它已经包含键if(iconViews.containsKey(position)){iconView = iconViews.get(position))};
一样。可能在这种情况下,没有大量的项目,所以平滑滚动不是必须的。
最后创建公共方法以获取Adapter之外的值传递item->getId()
Integer作为参数。例如:public ImageView getIconViewAt(int position) { return iconViews.get(position); }
。然后,从适配器
请参阅我的answer。
答案 5 :(得分:-1)
不是因为你在说
f_listView.getChildAt(i)
你应该在那个位置检索项目吗?
f_listView.getItemAtPosition(i)