获取不在视图中的 ListView 子项

18

我正在开发一个应用程序,尝试获取 ListView 的子项。为了实现这个目标,我编写了以下代码:

View listItem = mListView.getChildAt(i);

但这只适用于当前可见的子元素。我还需要访问那些不在当前视图中的子元素。我该如何做到这一点?

编辑:

将建议的方法与我已经使用的方法进行比较,我发现以下内容:

RelativeLayout listItem1 = (RelativeLayout) mListView.getAdapter().getView(i, null, mListView);
RelativeLayout listItem2 = (RelativeLayout) mListView.getChildAt(i);
Log.d("Checks", "listItem1: " + listItem1);
Log.d("Checks", "listItem2: " + listItem2);

08-27 14:16:56.628: D/Checks(15025): listItem1: android.widget.RelativeLayout@2c5f2920
08-27 14:16:56.628: D/Checks(15025): listItem2: android.widget.RelativeLayout@2c06d938
08-27 14:16:56.628: D/Checks(15025): listItem1: android.widget.RelativeLayout@2c72dfb0
08-27 14:16:56.628: D/Checks(15025): listItem2: android.widget.RelativeLayout@2bfabe50
08-27 14:16:56.638: D/Checks(15025): listItem1: android.widget.RelativeLayout@2c730c18
08-27 14:16:56.638: D/Checks(15025): listItem2: android.widget.RelativeLayout@2c0d3e38
08-27 14:16:56.638: D/Checks(15025): listItem1: android.widget.RelativeLayout@2c12ebc0
08-27 14:16:56.638: D/Checks(15025): listItem2: android.widget.RelativeLayout@2bddbf70
08-27 14:16:56.648: D/Checks(15025): listItem1: android.widget.RelativeLayout@2c131828
08-27 14:16:56.648: D/Checks(15025): listItem2: android.widget.RelativeLayout@2bdf3270
08-27 14:16:56.648: D/Checks(15025): listItem1: android.widget.RelativeLayout@2c140de0
08-27 14:16:56.648: D/Checks(15025): listItem2: android.widget.RelativeLayout@2c0c8d30

listItem2指向ListView中实际的View,这正是我想要的,但仅适用于可见视图。从日志文件可以看出,listItem1和listItem2不对应。

编辑2:

我想到了以下方法:

for (int i = 0; i < mListView.getCount(); i++) {
    RelativeLayout listItem = (RelativeLayout) mListView.getAdapter().getView(i, mListView.getChildAt(i), mListView);
}

这将正确地返回列表中所有可见项目的视图。但是,对于那些不在视线范围内的项目,它会返回不同的视图。

编辑3:

感谢nfirex的帮助,我现在有了一个可行的答案。即使它们不直接出现在视线范围内,它也会返回视图:

public View getViewByPosition(int position, ListView listView) {
    final int firstListItemPosition = listView.getFirstVisiblePosition();
    final int lastListItemPosition = firstListItemPosition + listView.getChildCount() - 1;

    if (position < firstListItemPosition || position > lastListItemPosition ) {
        return listView.getAdapter().getView(position, listView.getChildAt(position), listView);
    } else {
        final int childIndex = position - firstListItemPosition;
        return listView.getChildAt(childIndex);
    }
}
2个回答

35

你需要使用方法Adapter.getView()

final View view = mListView.getAdapter().getView(position, null, mListView);

更新:

您需要创建自己的方法,例如:

public View getViewByPosition(int position, ListView listView) {
    final int firstListItemPosition = listView.getFirstVisiblePosition();
    final int lastListItemPosition = firstListItemPosition + listView.getChildCount() - 1;

    if (position < firstListItemPosition || position > lastListItemPosition ) {
        return listView.getAdapter().getView(position, null, listView);
    } else {
        final int childIndex = position - firstListItemPosition;
        return listView.getChildAt(childIndex);
    }
}

2
这确实返回了一个视图。然而,我认为它返回的是一个新视图,而不是我想要的实际视图。 - Zero
你需要检索哪个视图?方法ListView.getChildAt(i)将返回其子项(它是ViewGroup的方法),该子项早先从适配器中获取。Adapter.getView(pos, oldView, parent)将返回新视图(如果oldView == null)或包含在Adapter.getItem(pos)中的数据的oldView,该数据由元素在数据列表中的位置决定。你想通过索引接收也保存在ListView中的视图吗? - nfirex
1
我正在尝试获取与getChildAt(i)相同的视图,但是对于不在视线中的视图(如果我屏幕上有8个项目并且我请求getChildAt(10),如果我向下滚动,它将在那里),我会收到NullPointerException。 - Zero
ListView中的第9项将再次获得位置1。 - Zero
我更新了答案。有一个问题 - 适配器本身不保留视图。ListView 保留视图并仅将它们提供给适配器以便用另一个子项重新填充它们。适配器只能创建或重新填充视图。 - nfirex
显示剩余4条评论

2
您可以使用此代码。
private static void initRecyclerBin(AbsListView view) {
        try {
            Field localField = AbsListView.class.getDeclaredField("mRecycler");
            localField.setAccessible(true);
            Object recyclerBin = localField.get(view);
            Class<?> clazz = Class.forName("android.widget.AbsListView$RecycleBin");
            Field scrapField = clazz.getDeclaredField("mScrapViews");
            scrapField.setAccessible(true);
            ArrayList<View>[] scrapViews;
            scrapViews = (ArrayList<View>[]) scrapField.get(recyclerBin);
            if (null != scrapViews) {
                int length = scrapViews.length;
                for (int i = 0, count = 0; i < length; i++) {
                    if (null != scrapViews[i] && !scrapViews[i].isEmpty()) {
                        for (int j = 0; j < scrapViews[i].size(); j++) {
                            scrapViews[i].get(j);//this is the scrapViews
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

以及ListView getChildViews()。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接