18

For an App I am working on, I'm trying to get the children of a ListView. To do this I have the following piece of code:

View listItem = mListView.getChildAt(i);

However, this only works for children that are in view. I need to also reach the children that are not in view. How would I do this?

EDIT:

Comparing the suggested methods to the one I was already using I find the following:

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 points to the actual View in the ListView, which is what I want except that it only works for Views that are in sight. You can see from the log file that listItem1 and listItem2 don't correspond.

EDIT 2:

I came up with the following:

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

This returns the Views correctly for all visible items in the list. However, it returns a different View for the ones that aren't in sight.

EDIT 3:

Thanks to nfirex I have a working answer. This will return Views even if they're not directly in sight:

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);
    }
}
Zero
  • 1,864
  • 3
  • 21
  • 39

2 Answers2

35

You need method Adapter.getView():

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

UPDATE:

You need to create your method. Something like this:

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);
    }
}
Gem
  • 1,516
  • 16
  • 21
nfirex
  • 1,523
  • 18
  • 24
  • 2
    This does indeed return a View. However, I think it returns a new View in stead of the actual one I want. – Zero Aug 27 '13 at 12:13
  • @Zero Which view you need to retrieve? Method ListView.getChildAt(i) will return it child (it is method of ViewGroup), that was early take from adapter. Adapter.getView(pos, oldView, parent) will return new view (if oldView == null) or oldView with data that contains in Adapter.getItem(pos) by position of element in your list of data. You want to receive views that also keeps in ListView by index? – nfirex Aug 27 '13 at 13:05
  • 1
    I'm trying to get the View that I also get with getChildAt(i), but for Views that are not in sight (if I have 8 items on screen and I request getChildAt(10), which will be there if I scroll down, I get a NullPointerException) – Zero Aug 27 '13 at 13:13
  • Item 9 in the ListView would get position 1 again – Zero Aug 27 '13 at 13:14
  • @Zero I'm update answer. There is one problem - Adapter is not keep views itself. ListView keep views and give them to adapter only for refill them with another child. Adapter can only create or refill views. – nfirex Aug 27 '13 at 13:33
  • I adapted your solution a bit, and it works! Thanks for the help :) . – Zero Aug 27 '13 at 14:04
  • @BillWoodger , yep, an editor is right. But I don't understand how I can accept changes. Can you help me please? – nfirex Jan 24 '14 at 12:29
  • The successful edit and the rejected edit have already been through the Review system, so you have no way to accept the edit automatically. You can edit the post yourself to make any changes you want. You click the edit link under the post itself. To see edits which have been previously made, click on the "edited [an amount of time ago] link above the user-image of the last editor (which at the moment is me). The rejected edit you can see from the link in my comment. Once you make the changes, we can delete these comments to be tidy. Clix on the x which appears when you hover on the comment. – Bill Woodger Jan 24 '14 at 12:51
  • It was amazing but I cannot get an **EditText value** which is _inside of the invisible area_ . how can I get that? – Suza Sep 20 '17 at 06:20
2

You can use this code

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();
        }
    }

and ListView getChildViews().

Czz
  • 21
  • 1