0

I want to measure the height of a ListView and expand it after loading some data. The ListAdapter choose different layouts for the items depending on the type of the data.

I tried this code:

public class ExpandedListView extends ListView {

[...]

@Override
protected void onDraw(Canvas canvas) {
    if (getCount() != 0) {
        params = getLayoutParams();
        int height = 0;
        for (int i = 0; i < getCount(); i++) {
            height += getChildAt(i).getMeasuredHeight();
            height += getDividerHeight();
        }
        params.height = height;
        setLayoutParams(params);
    }

    super.onDraw(canvas);
}

[...]

But I get a NullPointerException for getChildAt(i)

07-29 09:48:08.745: E/AndroidRuntime(21298): FATAL EXCEPTION: main
07-29 09:48:08.745: E/AndroidRuntime(21298): java.lang.NullPointerException
07-29 09:48:08.745: E/AndroidRuntime(21298):    at com.app.ExpandedListView.onDraw(ExpandedListView.java:24)
07-29 09:48:08.745: E/AndroidRuntime(21298):    at android.view.View.draw(View.java:13719)

Only one child is accessible, but getCount() gives me the value 38. Some other solutions for this problem multiply the getCount() with the height of the first Child at 0. But my items have different heights.

//params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0);

That's no solution for me. How can I receive the real height of my ListView?

EDIT: For better understanding: I've got a Parallax-Effect in my Activity. A ScrollView contains an ImageView as a Header and below a ListView. The ImageView scrolls a little bit slower than the ListView. So I can't use a normal ListView because of the ScrollView-Parent. enter image description here

A LinearLayout is no option because it behaves in combination with TextViews wrong and all TextViews are 2 lines tall maximum.

Brandon
  • 16,382
  • 12
  • 55
  • 88
Osiriz
  • 218
  • 1
  • 2
  • 15
  • maybe this will help you http://stackoverflow.com/a/5720141/1276374 – Boris Mocialov Jul 29 '13 at 08:17
  • Your link seems to be the solution I mentioned above. =( It only multiply the getCount() with the height of the first child. But my first child is not the tallest. So it's not high enough. – Osiriz Jul 29 '13 at 08:31
  • Ok, i think i understood your problem. what about this solution? http://stackoverflow.com/a/8627657/1276374 : `listviewElementsheight ` variable holds the height of all items based on their actual size – Boris Mocialov Jul 29 '13 at 08:41
  • `private int getTotalItemHeight() { ListAdapter adapter = (ListAdapter) getAdapter(); int listviewElementsheight = 0; for(int i =0; i < adapter.getCount(); i++) { View mView = adapter.getView(i, null, this); mView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); listviewElementsheight+= mView.getMeasuredHeight(); } return listviewElementsheight; }` doesn't work, because of NullPointerException at mView.measure(); – Osiriz Jul 29 '13 at 08:49
  • do you have getView method in your adapter? – Boris Mocialov Jul 29 '13 at 08:52
  • yes, there is the distinction of the data-types and the selection of the correct layout. – Osiriz Jul 29 '13 at 08:54
  • so you see all your items in the list when application is running? – Boris Mocialov Jul 29 '13 at 08:55
  • Exactly. If I set the height manually on a very high value, everything is correct. The only thing that doesn't work is to get more than one child with getChildAt(i) and so I'm not able to get the exact height of a ListView with different items. – Osiriz Jul 29 '13 at 09:01
  • Android is recycling the views of the Adapter, so maybe you are trying to access the view that is recycled, because then the reference would be null – Boris Mocialov Jul 29 '13 at 09:05
  • look here http://stackoverflow.com/a/10321746 – Boris Mocialov Jul 29 '13 at 09:06
  • 1
    which would mean that you will not be able to get all of your list items in onDraw method, since items are not yet in the memory – Boris Mocialov Jul 29 '13 at 09:07
  • Seems legit. No workaround available? Any ideas how to achieve my goal? – Osiriz Jul 29 '13 at 09:10
  • I still do not understand exactly what you are trying to achieve.. what do you mean by "expand it after loading some data" ? can you maybe show some picture of what the result is supposed to look like – Boris Mocialov Jul 29 '13 at 09:13
  • after looking at your picture, why do you need to expand it? you could just make it invisible, load data in adapter and make the list visible – Boris Mocialov Jul 29 '13 at 10:08
  • The ListView is a child of a ScrollView, above the ListView there is an ImageView with a header-picture. The ScrollView organize the Parallax-Effect and let the header scroll slower in the background of the ListView. The ListView should show the downloaded data from an adapter. If I do nothing with the ListView it is only 1 Item tall and scrollable without effect on the Parent-ScrollView. – Osiriz Jul 29 '13 at 10:21
  • I have same issue. Plz suggest any solution to how to get listview height,which have diff height listview item – SAndroidD Aug 08 '14 at 05:53

1 Answers1

0

Try this,

public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null) {
        return;
    }

    int desiredWidth = MeasureSpec.makeMeasureSpec(
            listView.getWidth(), MeasureSpec.UNSPECIFIED);
    int desiredHeight = MeasureSpec.makeMeasureSpec(
            listView.getHeight(), MeasureSpec.UNSPECIFIED);
    int totalHeight = 0;
    for (int i = 0; i < listAdapter.getCount(); i++) {
        View view = listAdapter.getView(i, null, listView);
        view.measure(desiredWidth, desiredHeight);
        totalHeight += view.getMeasuredHeight();
    }
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    listView.setLayoutParams(params);
}
vino
  • 13
  • 4