Android:从ListView访问子视图


108

我需要找出使用来显示的列表中一个元素的像素位置ListView。看来我应该得到一个TextView的然后使用getTop(),但我不知道如何获取的子视图ListView

更新:对于,子ViewGroup项与列表中的项目不一对一对应ListView。相反,ViewGroup的子项仅对应于当前可见的那些视图。因此getChildAt(),该操作基于的内部索引,ViewGroup并且不一定与所ListView使用列表中的位置有任何关系。

Answers:


215

请参阅:Android ListView:获取可见项的数据索引, 并与上面Feet的部分答案结合,可以为您提供以下信息:

int wantedPosition = 10; // Whatever position you're looking for
int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;
// Say, first visible position is 8, you want position 10, wantedChild will now be 2
// So that means your view is child #2 in the ViewGroup:
if (wantedChild < 0 || wantedChild >= listView.getChildCount()) {
  Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
  return;
}
// Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
View wantedView = listView.getChildAt(wantedChild);

这样做的好处是您不必遍历ListView的子级,这可能会降低性能。


10
很好的答案,但是当列表中有标题视图时,效果并不理想。分配给的firstPosition应该是int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount();解决这个问题。
pospi 2011年

@pospi:谢谢,很好!我已经更新了我的答案以说明这一点。

好的答案在大多数情况下都是可行的,但是我不明白为什么您会认为子视图以它们在子视图数组中的顺序出现。由于视图可以重用,我们如何确定第一个视图不代表最后一个可见视图?
维克多·德尼索夫

2
@VictorDenisov:这只能在UI线程上发生;因此,在执行此代码时,UI线程将被阻塞,因此子视图是固定的,不会被修改。 ListView已在处理“移动”子视图回收旧后围绕convertViewS,等等,这样你就可以被保证ListView.getChildAt(0) 实际上从适配器第一贴附视图。它可能不完全可见(甚至可能根本不可见,这取决于在ListView回收认为“滚动”的视图之前,“可见性”的阈值)

1
@Matheus不是Android ListView的工作方式。如果列表项是关闭屏幕,其观点已经被回收并为其他列表项目之一重用在屏幕上。如果需要,您应该重新考虑如何使用ListView。
2015年

17

此代码更易于使用:

 View rowView = listView.getChildAt(viewIndex);//The item number in the List View
    if(rowView != null)
        {
           // Your code here
        }

9
并不总是有效。getChildAt从第一可见行开始计数,而不是从数据顶部开始计数。
SteelBytes 2012年

13
ViewID参数令人困惑。这是一个索引(或位置)。视图ID是由aapt工具生成的完全任意整数。
约翰·佩格里姆

6

快速搜索ListView类的文档已启用从ViewGroup继承的getChildCount()和getChildAt()方法。您可以使用它们遍历它们吗?我不确定,但是值得一试。

在这里找到


1
我已经尝试过了,可以进行选择。它通常可以工作,但有时会出现一一错误,并且不可靠。我不推荐它。
Timmmm 2012年

感谢Timmmm,我实际上并没有尝试过,只是在文档中找到了它。
2012年

5
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
        View v;
        int count = parent.getChildCount();
        v = parent.getChildAt(position);
        parent.requestChildFocus(v, view);
        v.setBackground(res.getDrawable(R.drawable.transparent_button));
        for (int i = 0; i < count; i++) {
            if (i != position) {
                v = parent.getChildAt(i);
                v.setBackground(res.getDrawable(R.drawable.not_clicked));
            }
        }
    }
});

基本上,创建两个Drawable-一个是透明的,另一个是所需的颜色。请求将焦点放在单击的位置(int position已定义),并更改所述行的颜色。然后遍历父级ListView,并相应地更改所有其他行。这说明了用户listview多次单击的时间。这是通过对中的每一行使用自定义布局来完成的ListView。(非常简单,只需使用TextView -请勿设置可聚焦或可单击!)。

不需要自定义适配器-使用 ArrayAdapter


getChildAt是相对于当前滚动项的。如果您稍微滚动一下列表,它将停止工作。
nurettin '16

4
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);

1
详细说明
innoSPG '16

-9

假设您知道元素在ListView中的位置:

  View element = listView.getListAdapter().getView(position, null, null);

然后,您应该能够调用getLeft()和getTop()来确定屏幕位置上的元素。


43
getView()填充列表时,由ListView在内部调用。您不应该使用它来获取列表中该位置的视图,因为getView()使用null进行调用convertView会导致适配器从适配器的布局资源中充气一个新视图(不会获得已经显示的视图)。

1
偶数位置将是可视屏幕中的位置,而不是适配器的数据源位置。
维卡斯

@jasonhudgins这是我一直使用的方法,我认为这是最好的方法,但是当我尝试使子视图中的进度条不可见时,相反,它使listvew中的所有进度条都不可见....所有被接受的答案都可以解决问题
Edijae Crusar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.